Skip to content

Commit 53a5cb8

Browse files
mdh1418Mitchell Hwangadegeo
authored
[mono] Add iOS app sample using mono runtime (#3931)
* Initial port of iOS sample * Remove dependency on dotnet.sh and MonoAotCompiler * Remove reference to in-tree runtime pack * Modify path to mobile.tasks * Directly reference TargetFramework * Modify AppleAppBuilder config * Use forward slash in paths * Remove in-tree runtime pack reference * Add TargetArch remove MNCARPD * Add NuGet and BuildAppBundle after publish * Minimal working sample * Modify sample to rely on nuget package instead * Remove Debugging target * Add iOS sample nuget package * Add custom UI file * Clean up project file * Update iOS sample Auto Layout * Add action replace iOS with name * Touch up string replacement * Add mono readme and iOS specific readme * Update assembly target version * Clean up README * Clean up notes in README * Add brackets around bare url in README * Remove trailing space and add blank line around list * Reference dotnet6 NuGet feed * Remove nuget local repositoryPath * Reword header for clarification * Fix nupkg version match * Use PropertyPath instead of NuGetPackageRoot * Remove unnecessary dependencies * Add softcode for runtime identifier * Touch up README * Add build of dotnet sdk to prereqs * Override with .NET 6 SDK * Fix dotnet version and add installation instructions * Update target framework to target net6.0 * Remove handlers and MonoPInvoke Attribute * Move TargetArchitecture to project scope * Rename Program to iOSSampleApp and trim assemblies * Minor fixes; pulled prereqs into sample readme Co-authored-by: Mitchell Hwang <mitchell.hwang@microsoft.com> Co-authored-by: Andy De George <67293991+adegeo@users.noreply.github.com>
1 parent 18e31a5 commit 53a5cb8

File tree

7 files changed

+431
-0
lines changed

7 files changed

+431
-0
lines changed

core/mono-samples/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Sample .NET apps using the Mono runtime
2+
3+
This folder contains sample code demonstrating how to build mobile (iOS, Android, Browser WebAssembly) apps with the mono runtime. The requirements for each sample can be found within the corresponding folder, and each sample can be ran using `dotnet publish`.
4+
5+
## Prerequisites
6+
7+
.NET SDK version 6.0.100-alpha.1.20531.2 is needed to run these samples. To install a specific version of the dotnet sdk, download the latest stable version of the dotnet-install script:
8+
9+
- Bash (Linux/macOS): <https://dot.net/v1/dotnet-install.sh>
10+
- PowerShell (Windows): <https://dot.net/v1/dotnet-install.ps1>
11+
12+
Install version .NET version **6.0.100-alpha.1.20531.2**:
13+
14+
```bash
15+
./dotnet-install.sh --version 6.0.100-alpha.1.20531.2
16+
```
17+
18+
```powershell
19+
./dotnet-install.ps1 -Version 6.0.100-alpha.1.20531.2
20+
```
21+
22+
For more information, see [dotnet-install script reference](https://docs.microsoft.com/dotnet/core/tools/dotnet-install-script)

core/mono-samples/iOS/NuGet.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<add key="dotnet6" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json" />
5+
</packageSources>
6+
</configuration>

core/mono-samples/iOS/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
languages:
3+
- csharp
4+
products:
5+
- dotnet-core
6+
page_type: sample
7+
name: "iOS Sample: Simple greeting and counter (C#)"
8+
description: "An iOS application that contains an example of embedding the mono runtime to invoke unmanaged code with C#."
9+
urlFragment: "mono-ios-csharp"
10+
---
11+
12+
# iOS Sample: Simple greeting and counter (C#)
13+
14+
In this sample, the mono runtime is used to invoke Objective-c unmanaged code (main.m) from the C# managed side (iOSSampleApp.cs) and vice versa. With the sample running, you can enter your name and click the corresponding button to modify the greeting message as well as clicking a button to increment a counter.
15+
16+
> [!NOTE]
17+
> The purpose of this sample is to demonstrate the concept of building an iOS application on top of the mono runtime. The mono runtime headers should be supplied through the build process.
18+
19+
## Sample Prerequisites
20+
21+
This sample will only run on macOS as it requires Xcode and an iOS simulator.
22+
23+
- Xcode: Any version should work with this sample (download Xcode at <https://developer.apple.com/xcode/>).
24+
- iOS simulator 8.0 or greater.
25+
- .NET sdk 6.0.100-alpha.1.20531.2 (Installation instructions in parent directory).
26+
27+
To install a specific version of the dotnet sdk, download the latest stable version of the dotnet-install script:
28+
29+
- Bash (Linux/macOS): <https://dot.net/v1/dotnet-install.sh>
30+
- PowerShell (Windows): <https://dot.net/v1/dotnet-install.ps1>
31+
32+
Install version .NET version **6.0.100-alpha.1.20531.2**:
33+
34+
```bash
35+
./dotnet-install.sh --version 6.0.100-alpha.1.20531.2
36+
```
37+
38+
```powershell
39+
./dotnet-install.ps1 -Version 6.0.100-alpha.1.20531.2
40+
```
41+
42+
> [!NOTE]
43+
> Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name.
44+
45+
## Building the sample
46+
47+
The source code includes an MSBuild project file for C# (a _.csproj_ file) that targets .NET 6.0. After downloading the _.zip_ file, be sure to have the iOS simulator open and modify `iPhone 11` in `iOSSampleApp.csproj` to the simulator's name. To run the sample, open the command line, navigate to the downloaded folder, and run `dotnet publish`.

core/mono-samples/iOS/global.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"sdk": {
3+
"version": "6.0.100-alpha.1.20531.2",
4+
"rollForward": "major",
5+
"allowPrerelease": true
6+
}
7+
}

core/mono-samples/iOS/iOSSampleApp.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using System.Runtime.InteropServices;
8+
9+
public static class iOSSampleApp
10+
{
11+
// Defined in main.m
12+
[DllImport("__Internal")]
13+
private extern static void ios_set_text(string value);
14+
15+
[DllImport("__Internal")]
16+
private extern static void ios_greet_name(string value);
17+
18+
[DllImport("__Internal")]
19+
private extern static void ios_register_counter_increment(Action action);
20+
21+
[DllImport("__Internal")]
22+
private extern static void ios_register_name_greet(Action<string> action);
23+
24+
private static int counter = 1;
25+
26+
// Called by native code, see main.m
27+
private static void IncrementCounter()
28+
{
29+
ios_set_text($"Clicked {counter++} times!");
30+
}
31+
32+
private static void GreetName(string name)
33+
{
34+
ios_greet_name(name);
35+
}
36+
37+
public static async Task Main(string[] args)
38+
{
39+
// Register a managed callback (will be called by UIButton, see main.m)
40+
// Also, keep the handler alive so GC won't collect it.
41+
ios_register_counter_increment(IncrementCounter);
42+
ios_register_name_greet(GreetName);
43+
44+
const string msg = "Hello World!";
45+
for (int i = 0; i < msg.Length; i++)
46+
{
47+
// a kind of an animation
48+
ios_set_text(msg.Substring(0, i + 1));
49+
await Task.Delay(100);
50+
}
51+
52+
Console.WriteLine("Done!");
53+
await Task.Delay(-1);
54+
}
55+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net6.0</TargetFramework>
4+
<TargetArchitecture>x64</TargetArchitecture>
5+
<RuntimeIdentifier>ios-$(TargetArchitecture)</RuntimeIdentifier>
6+
<OutputType>Exe</OutputType>
7+
<PublishTrimmed>True</PublishTrimmed>
8+
<TrimMode>link</TrimMode>
9+
<Configuration>Release</Configuration>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="Microsoft.NET.Runtime.iOS.Sample.Mono" Version="6.0.0-*" GeneratePathProperty="true" />
14+
</ItemGroup>
15+
16+
<UsingTask TaskName="AppleAppBuilderTask"
17+
AssemblyFile="$(PkgMicrosoft_NET_Runtime_iOS_Sample_Mono)\tools\net6.0\AppleAppBuilder.dll" />
18+
19+
<Target Name="BuildAppBundle" AfterTargets="Publish">
20+
<PropertyGroup>
21+
<AppDir>$(MSBuildThisFileDirectory)$(PublishDir)</AppDir>
22+
<IosSimulator Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'x86'">iPhone 11</IosSimulator>
23+
<Optimized Condition="'$(Configuration)' == 'Release'">True</Optimized>
24+
</PropertyGroup>
25+
26+
<ItemGroup>
27+
<BundleAssemblies Include="$(AppDir)\*.dll" />
28+
</ItemGroup>
29+
30+
<AppleAppBuilderTask
31+
ProjectName="HelloiOS"
32+
AppDir="$(AppDir)"
33+
MonoRuntimeHeaders="%(ResolvedRuntimePack.PackageDirectory)\runtimes\$(RuntimeIdentifier)\native\include\mono-2.0"
34+
MainLibraryFileName="$(MSBuildThisFileName).dll"
35+
Assemblies="@(BundleAssemblies)"
36+
OutputDirectory="$(AppDir)\app"
37+
Optimized="$(Optimized)"
38+
Arch="$(TargetArchitecture)"
39+
BuildAppBundle="True"
40+
GenerateXcodeProject="True"
41+
NativeMainSource="$(MSBuildThisFileDirectory)main.m">
42+
<Output TaskParameter="AppBundlePath" PropertyName="AppBundlePath" />
43+
<Output TaskParameter="XcodeProjectPath" PropertyName="XcodeProjectPath" />
44+
</AppleAppBuilderTask>
45+
46+
<Message Importance="High" Text="Xcode: $(XcodeProjectPath)" />
47+
<Message Importance="High" Text="App: $(AppBundlePath)" />
48+
<Message Importance="High" Text="Restarting device" />
49+
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl shutdown &quot;$(IosSimulator)&quot;" ContinueOnError="WarnAndContinue" />
50+
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl boot &quot;$(IosSimulator)&quot;" />
51+
<Exec Condition="'$(IosSimulator)' != ''" Command="open -a Simulator" />
52+
<Message Importance="High" Text="Installing application" />
53+
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl install &quot;$(IosSimulator)&quot; $(AppBundlePath)" />
54+
<Message Importance="High" Text="Launching application" />
55+
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl launch --console booted net.dot.HelloiOS" />
56+
</Target>
57+
</Project>

0 commit comments

Comments
 (0)