Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>Microsoft.ML.OnnxRuntime.InferenceSample.Maui</RootNamespace>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
<PropertyGroup Condition="('$(OrtPackageId)' == 'Microsoft.ML.OnnxRuntime' OR
'$(OrtPackageId)' == 'Microsoft.ML.OnnxRuntime.Azure') AND
'$(IncludeMobileTargets)' == 'true'">
<MobileTargets>net8.0-android;net8.0-ios;net8.0-maccatalyst</MobileTargets>
<MobileTargets>net9.0-android;net9.0-ios;net9.0-maccatalyst</MobileTargets>
</PropertyGroup>

<PropertyGroup Condition="'$(OrtPackageId)' == 'Microsoft.ML.OnnxRuntime.Training' AND
'$(IncludeMobileTargets)' == 'true'">
<MobileTargets>net8.0-android</MobileTargets>
<MobileTargets>net9.0-android</MobileTargets>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
This project will run the Android MAUI tests on BrowserStack, which allows you to run automated tests on a variety of mobile devices.

## Context
Microsoft.ML.OnnxRuntime.Tests.MAUI uses DeviceRunners.VisualRunners to allow running the unit tests (found in Microsoft.ML.OnnxRuntime.Tests.Common) across multiple devices. DeviceRunners.VisualRunners provides a simple UI with a button that will run the unit tests and a panel with the unit test results.
Microsoft.ML.OnnxRuntime.Tests.MAUI uses DeviceRunners.VisualRunners to allow running the unit tests (found in Microsoft.ML.OnnxRuntime.Tests.Common) across multiple devices. DeviceRunners.VisualRunners provides a simple UI with a button that will run the unit tests and a panel with the unit test results.

In order to automate the process of running the unit tests across mobile devices, Appium is used for UI testing orchestration (it provides a way to interact with the UI), and BrowserStack automatically runs these Appium tests across different mobile devices.

This project does not include the capability to start an Appium server locally or attach to a local emulator or device.
This project does not include the capability to start an Appium server locally or attach to a local emulator or device.

## Build & run instructions
### Requirements
Expand All @@ -22,8 +22,8 @@ This project does not include the capability to start an Appium server locally o

### Run instructions
1. Build the Microsoft.ML.OnnxRuntime.Tests.MAUI project into a signed APK.
1. Run the following: `dotnet publish -c Release -f net8.0-android` in the Microsoft.ML.OnnxRuntime.Tests.MAUI directory.
2. Search for the APK files generated. They should be located in `bin\Release\net8.0-android\publish`.
1. Run the following: `dotnet publish -c Release -f net9.0-android` in the Microsoft.ML.OnnxRuntime.Tests.MAUI directory.
2. Search for the APK files generated. They should be located in `bin\Release\net9.0-android\publish`.
3. If they're in a different location, edit the `browserstack.yml` file to target the path to the signed APK.
2. Ensure you've set the BrowserStack credentials as environment variables.
3. Run the following in the Microsoft.ML.OnnxRuntime.Tests.Android.BrowserStack directory: `dotnet test`
Expand All @@ -36,13 +36,13 @@ This project does not include the capability to start an Appium server locally o
- [Integration guide](https://www.browserstack.com/docs/app-automate/appium/getting-started/c-sharp/nunit/integrate-your-tests#CLI)

### Troubleshooting
- Issues building the MAUI app:
- Issues building the MAUI app:
- Make sure that the maui and maui-android workloads are installed correctly by running `dotnet workload list`
- If you believe the issues are workload related, you can also try running `dotnet workload repair` (this has personally never worked for me)
- Try running `dotnet clean`. However, this does not fully remove all the previous intermediaries. If you're still running into the errors, manually deleting the bin and obj folders can sometimes resolve them.
- Try running `dotnet clean`. However, this does not fully remove all the previous intermediaries. If you're still running into the errors, manually deleting the bin and obj folders can sometimes resolve them.
- After building the MAUI app, try installing on an emulator and clicking the "Run All" button to ensure that everything is working. (If you are missing the ONNXRuntime package, it will not show up as an error until you click "Run All".)
- Running the MAUI app from Visual Studio will not replicate running it through BrowserStack. Instead, use `adb install [path to signed apk]` to install the app then use the emulator to launch the app.
- Issues with the Android.BrowserStack test app: there is an Appium Doctor package on npm -- run `npm install @appium/doctor --location=global` then `appium-doctor --android` and follow the directed instructions. Some errors with Appium on Android will not appear until runtime.
- Connection refused by Appium server: this can happen if you already have an Appium server running locally. If you do, stop the Appium server then try `dotnet test` again.
- App is crashing on BrowserStack or it emits an error that it cannot run this APK file: make sure that you are passing in the correct signed APK from the publish folder.
- App is crashing on BrowserStack or it emits an error that it cannot run this APK file: make sure that you are passing in the correct signed APK from the publish folder.
- It appears that a test runs on CLI but a build is not launched on BrowserStack: this happens when the BrowserStack Test Adapter cannot find the browserstack.yml file (which has to be named "browserstack.yml" -- do not be tricked by BrowserStack's article on custom-named configuration files)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
app: ..\Microsoft.ML.OnnxRuntime.Tests.MAUI\bin\Release\net8.0-android\publish\ORT.CSharp.Tests.MAUI-Signed.apk
app: ..\Microsoft.ML.OnnxRuntime.Tests.MAUI\bin\Release\net9.0-android\publish\ORT.CSharp.Tests.MAUI-Signed.apk
platforms:
- platformName: android
deviceName: Samsung Galaxy S22 Ultra
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
Disabling those targets until the issues are resolved. -->
<!-- <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> -->

<TargetFrameworks>net8.0-android</TargetFrameworks>
<TargetFrameworks>net9.0-android</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>

<!-- Note for MacCatalyst:
Expand Down
2 changes: 1 addition & 1 deletion csharp/tools/MauiModelTester/MauiModelTester.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0-ios;net8.0-android34.0</TargetFrameworks>
<TargetFrameworks>net9.0-ios;net9.0-android35.0</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>MauiModelTester</RootNamespace>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ stages:
targetType: 'inline'
script: |
dotnet nuget add source $(Pipeline.Workspace)/build/drop-signed-nuget-${{ parameters.ArtifactSuffix }} --name local-nuget
dotnet publish -c Release --property:UsePrebuiltNativePackage=true --property:CurrentOnnxRuntimeVersion=$(NuGetPackageVersionNumber) -f net8.0-android
dotnet publish -c Release --property:UsePrebuiltNativePackage=true --property:CurrentOnnxRuntimeVersion=$(NuGetPackageVersionNumber) -f net9.0-android
workingDirectory: '$(Build.SourcesDirectory)\csharp\test\Microsoft.ML.OnnxRuntime.Tests.MAUI'

- task: BrowserStackConfig@0
Expand All @@ -55,7 +55,7 @@ stages:

- task: BrowserStackAppUploader@0
inputs:
appPath: '$(Build.SourcesDirectory)\csharp\test\Microsoft.ML.OnnxRuntime.Tests.MAUI\bin\Release\net8.0-android\publish\ORT.CSharp.Tests.MAUI-Signed.apk'
appPath: '$(Build.SourcesDirectory)\csharp\test\Microsoft.ML.OnnxRuntime.Tests.MAUI\bin\Release\net9.0-android\publish\ORT.CSharp.Tests.MAUI-Signed.apk'
appCustomId: 'Appium-Android-CI'

- task: PowerShell@2
Expand Down
113 changes: 69 additions & 44 deletions tools/nuget/generate_nuspec_for_native_nuget.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@
import argparse
import os
import re
import shutil
import sys
from pathlib import Path

# These platform version values are the default target platform versions for .NET 9 from the table here:
# https://learn.microsoft.com/en-us/dotnet/standard/frameworks#os-version-in-tfms
platform_version_android = "35.0"
platform_version_ios = "18.0"
platform_version_maccatalyst = "18.0"
Comment thread
edgchen1 marked this conversation as resolved.


# What does the names of our C API tarball/zip files looks like
# os: win, linux, osx
Expand Down Expand Up @@ -279,17 +286,17 @@ def generate_dependencies(xml_text, package_name, version):
xml_text.append("</group>")
if package_name == "Microsoft.ML.OnnxRuntime":
xml_text.append('<group targetFramework="native" />')
# Support net8.0-android
xml_text.append('<group targetFramework="net8.0-android31.0">')
xml_text.append('<dependency id="Microsoft.ML.OnnxRuntime.Managed"' + ' version="' + version + '"/>')
# Support Android
xml_text.append(f'<group targetFramework="net9.0-android{platform_version_android}">')
xml_text.append(f'<dependency id="Microsoft.ML.OnnxRuntime.Managed" version="{version}"/>')
xml_text.append("</group>")
# Support net8.0-ios
xml_text.append('<group targetFramework="net8.0-ios15.4">')
xml_text.append('<dependency id="Microsoft.ML.OnnxRuntime.Managed"' + ' version="' + version + '"/>')
# Support iOS
xml_text.append(f'<group targetFramework="net9.0-ios{platform_version_ios}">')
xml_text.append(f'<dependency id="Microsoft.ML.OnnxRuntime.Managed" version="{version}"/>')
xml_text.append("</group>")
# Support net8.0-maccatalyst
xml_text.append('<group targetFramework="net8.0-maccatalyst14.0">')
xml_text.append('<dependency id="Microsoft.ML.OnnxRuntime.Managed"' + ' version="' + version + '"/>')
# Support MacCatalyst
xml_text.append(f'<group targetFramework="net9.0-maccatalyst{platform_version_maccatalyst}">')
xml_text.append(f'<dependency id="Microsoft.ML.OnnxRuntime.Managed" version="{version}"/>')
xml_text.append("</group>")
# Support Native C++
if include_dml:
Expand Down Expand Up @@ -352,6 +359,10 @@ def generate_metadata(line_list, args):
line_list += metadata_list


def copy_file(src_path, dst_path):
shutil.copyfile(src_path, dst_path)


def generate_files(line_list, args):
files_list = ["<files>"]

Expand Down Expand Up @@ -417,7 +428,6 @@ def generate_files(line_list, args):
"onnx_test_runner": "onnx_test_runner.exe",
}

copy_command = "copy"
runtimes_target = '" target="runtimes\\win-'
else:
nuget_dependencies = {
Expand All @@ -436,7 +446,6 @@ def generate_files(line_list, args):
"onnx_test_runner": "onnx_test_runner",
}

copy_command = "cp"
runtimes_target = '" target="runtimes\\linux-'

if is_windowsai_package:
Expand Down Expand Up @@ -1007,7 +1016,7 @@ def _files_list_append(key: str):
"netstandard",
args.package_name + ".props",
)
os.system(copy_command + " " + source_props + " " + target_props)
copy_file(source_props, target_props)
files_list.append("<file src=" + '"' + target_props + '" target="' + build_dir + '\\native" />')
if not is_snpe_package and not is_qnn_package:
files_list.append("<file src=" + '"' + target_props + '" target="' + build_dir + '\\netstandard2.0" />')
Expand All @@ -1026,112 +1035,128 @@ def _files_list_append(key: str):
"netstandard",
args.package_name + ".targets",
)
os.system(copy_command + " " + source_targets + " " + target_targets)
copy_file(source_targets, target_targets)
files_list.append("<file src=" + '"' + target_targets + '" target="' + build_dir + '\\native" />')
if not is_snpe_package and not is_qnn_package:
files_list.append("<file src=" + '"' + target_targets + '" target="' + build_dir + '\\netstandard2.0" />')
files_list.append("<file src=" + '"' + target_targets + '" target="' + build_dir + '\\netstandard2.1" />')

# Process xamarin targets files
if args.package_name == "Microsoft.ML.OnnxRuntime":
net8_android_source_targets = os.path.join(
net9_android_source_targets = os.path.join(
args.sources_path,
"csharp",
"src",
"Microsoft.ML.OnnxRuntime",
"targets",
"net8.0-android",
"net9.0-android",
"targets.xml",
)
net8_android_target_targets = os.path.join(
net9_android_target_targets = os.path.join(
args.sources_path,
"csharp",
"src",
"Microsoft.ML.OnnxRuntime",
"targets",
"net8.0-android",
"net9.0-android",
args.package_name + ".targets",
)

net8_ios_source_targets = os.path.join(
args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "net8.0-ios", "targets.xml"
net9_ios_source_targets = os.path.join(
args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "net9.0-ios", "targets.xml"
)
net8_ios_target_targets = os.path.join(
net9_ios_target_targets = os.path.join(
args.sources_path,
"csharp",
"src",
"Microsoft.ML.OnnxRuntime",
"targets",
"net8.0-ios",
"net9.0-ios",
args.package_name + ".targets",
)

net8_maccatalyst_source_targets = os.path.join(
net9_maccatalyst_source_targets = os.path.join(
args.sources_path,
"csharp",
"src",
"Microsoft.ML.OnnxRuntime",
"targets",
"net8.0-maccatalyst",
"net9.0-maccatalyst",
"_._",
)
net9_maccatalyst_target_targets = net9_maccatalyst_source_targets

net8_maccatalyst_target_targets = os.path.join(
args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "net8.0-maccatalyst", "_._"
)

os.system(copy_command + " " + net8_android_source_targets + " " + net8_android_target_targets)
os.system(copy_command + " " + net8_ios_source_targets + " " + net8_ios_target_targets)
os.system(copy_command + " " + net8_maccatalyst_source_targets + " " + net8_maccatalyst_target_targets)
copy_file(net9_android_source_targets, net9_android_target_targets)
copy_file(net9_ios_source_targets, net9_ios_target_targets)

files_list.append(
"<file src=" + '"' + net8_android_target_targets + '" target="build\\net8.0-android31.0" />'
"<file src="
+ '"'
+ net9_android_target_targets
+ f'" target="build\\net9.0-android{platform_version_android}" />'
)
files_list.append(
"<file src=" + '"' + net8_android_target_targets + '" target="buildTransitive\\net8.0-android31.0" />'
"<file src="
+ '"'
+ net9_android_target_targets
+ f'" target="buildTransitive\\net9.0-android{platform_version_android}" />'
)

files_list.append("<file src=" + '"' + net8_ios_target_targets + '" target="build\\net8.0-ios15.4" />')
files_list.append(
"<file src=" + '"' + net8_ios_target_targets + '" target="buildTransitive\\net8.0-ios15.4" />'
"<file src=" + '"' + net9_ios_target_targets + f'" target="build\\net9.0-ios{platform_version_ios}" />'
)
files_list.append(
"<file src=" + '"' + net8_maccatalyst_target_targets + '" target="build\\net8.0-maccatalyst14.0" />'
"<file src="
+ '"'
+ net9_ios_target_targets
+ f'" target="buildTransitive\\net9.0-ios{platform_version_ios}" />'
)
files_list.append(
"<file src="
+ '"'
+ net9_maccatalyst_target_targets
+ f'" target="build\\net9.0-maccatalyst{platform_version_maccatalyst}" />'
)
files_list.append(
"<file src="
+ '"'
+ net8_maccatalyst_target_targets
+ '" target="buildTransitive\\net8.0-maccatalyst14.0" />'
+ net9_maccatalyst_target_targets
+ f'" target="buildTransitive\\net9.0-maccatalyst{platform_version_maccatalyst}" />'
)

# Process Training specific targets and props
if args.package_name == "Microsoft.ML.OnnxRuntime.Training":
net8_android_source_targets = os.path.join(
net9_android_source_targets = os.path.join(
args.sources_path,
"csharp",
"src",
"Microsoft.ML.OnnxRuntime",
"targets",
"net8.0-android",
"net9.0-android",
"targets.xml",
)
net8_android_target_targets = os.path.join(
net9_android_target_targets = os.path.join(
args.sources_path,
"csharp",
"src",
"Microsoft.ML.OnnxRuntime",
"targets",
"net8.0-android",
"net9.0-android",
args.package_name + ".targets",
)

os.system(copy_command + " " + net8_android_source_targets + " " + net8_android_target_targets)
copy_file(net9_android_source_targets, net9_android_target_targets)
files_list.append(
"<file src=" + '"' + net8_android_target_targets + '" target="build\\net8.0-android31.0" />'
"<file src="
+ '"'
+ net9_android_target_targets
+ f'" target="build\\net9.0-android{platform_version_android}" />'
)
files_list.append(
"<file src=" + '"' + net8_android_target_targets + '" target="buildTransitive\\net8.0-android31.0" />'
"<file src="
+ '"'
+ net9_android_target_targets
+ f'" target="buildTransitive\\net9.0-android{platform_version_android}" />'
)

# README
Expand Down
Loading