Skip to content

[mono] Add iOS app sample using mono runtime #3931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 41 commits into from
Nov 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
2945ca0
Initial port of iOS sample
Sep 29, 2020
a8a7887
Remove dependency on dotnet.sh and MonoAotCompiler
Sep 29, 2020
5455b45
Remove reference to in-tree runtime pack
Sep 29, 2020
7d20c40
Modify path to mobile.tasks
Sep 29, 2020
4b5e9cb
Directly reference TargetFramework
Sep 29, 2020
c5d22c7
Modify AppleAppBuilder config
Sep 29, 2020
e87abe0
Use forward slash in paths
Sep 29, 2020
6badecd
Remove in-tree runtime pack reference
Sep 29, 2020
06d67cd
Add TargetArch remove MNCARPD
Sep 29, 2020
33b7058
Add NuGet and BuildAppBundle after publish
Sep 29, 2020
4a62af7
Minimal working sample
Sep 30, 2020
894f033
Modify sample to rely on nuget package instead
Oct 1, 2020
a59c56d
Remove Debugging target
Oct 1, 2020
93017d7
Add iOS sample nuget package
Oct 5, 2020
2bf168f
Add custom UI file
Oct 13, 2020
dbfda59
Clean up project file
Oct 13, 2020
b1805b3
Update iOS sample Auto Layout
Oct 14, 2020
2ad509f
Add action replace iOS with name
Oct 14, 2020
17e9c1c
Touch up string replacement
Oct 14, 2020
9dbdfd7
Add mono readme and iOS specific readme
Oct 15, 2020
49691c4
Update assembly target version
Oct 19, 2020
93683dd
Clean up README
Oct 19, 2020
0d3b5b8
Clean up notes in README
Oct 19, 2020
be096f1
Add brackets around bare url in README
Oct 19, 2020
08f2cf7
Remove trailing space and add blank line around list
Oct 19, 2020
5947c52
Reference dotnet6 NuGet feed
Oct 20, 2020
c9b2820
Remove nuget local repositoryPath
Oct 20, 2020
2d79b0a
Reword header for clarification
Oct 20, 2020
a31b034
Fix nupkg version match
Oct 20, 2020
228d185
Use PropertyPath instead of NuGetPackageRoot
Oct 20, 2020
c6c11eb
Remove unnecessary dependencies
Oct 20, 2020
54c640e
Add softcode for runtime identifier
Oct 20, 2020
1ee0239
Touch up README
Oct 20, 2020
35558ad
Add build of dotnet sdk to prereqs
Oct 20, 2020
2c3b026
Override with .NET 6 SDK
Oct 21, 2020
b1b4658
Fix dotnet version and add installation instructions
Nov 2, 2020
2bb0b00
Update target framework to target net6.0
Nov 2, 2020
f338c17
Remove handlers and MonoPInvoke Attribute
Nov 2, 2020
590a8bb
Move TargetArchitecture to project scope
Nov 3, 2020
813b970
Rename Program to iOSSampleApp and trim assemblies
Nov 11, 2020
cfaa203
Minor fixes; pulled prereqs into sample readme
adegeo Nov 11, 2020
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
22 changes: 22 additions & 0 deletions core/mono-samples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Sample .NET apps using the Mono runtime

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`.

## Prerequisites

.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:

- Bash (Linux/macOS): <https://dot.net/v1/dotnet-install.sh>
- PowerShell (Windows): <https://dot.net/v1/dotnet-install.ps1>

Install version .NET version **6.0.100-alpha.1.20531.2**:

```bash
./dotnet-install.sh --version 6.0.100-alpha.1.20531.2
```

```powershell
./dotnet-install.ps1 -Version 6.0.100-alpha.1.20531.2
```

For more information, see [dotnet-install script reference](https://docs.microsoft.com/dotnet/core/tools/dotnet-install-script)
6 changes: 6 additions & 0 deletions core/mono-samples/iOS/NuGet.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="dotnet6" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json" />
</packageSources>
</configuration>
47 changes: 47 additions & 0 deletions core/mono-samples/iOS/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
languages:
- csharp
products:
- dotnet-core
page_type: sample
name: "iOS Sample: Simple greeting and counter (C#)"
description: "An iOS application that contains an example of embedding the mono runtime to invoke unmanaged code with C#."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need the URL it will be hosted at in the samples browser when published: https://review.docs.microsoft.com/en-us/samples/browse/?branch=master

Suggested change
description: "An iOS application that contains an example of embedding the mono runtime to invoke unmanaged code with C#."
description: "An iOS application that contains an example of embedding the mono runtime to invoke unmanaged code with C#."
urlFragment: "mono-ios-csharp"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the url be generated automatically from adding this line or are there other actionables I need to take to get the sample hosted at the url?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IFAIK you just need to add this line. I have heard rumors though that the samples browser doesn't automatically import samples and you need to file a ticket. I've heard it's "supposed" to be automated but it never shows up and when you ask about it, it magically shows up, as if someone is somewhere pushing a button every time.

@IEvangelist true?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My experience is that it takes a long time, roughly a week or so - but it does eventually make its way there. There have been a few times too where it has gotten stuck with no reason why, then you have to ask the right people who have access to get it moved.

urlFragment: "mono-ios-csharp"
---

# iOS Sample: Simple greeting and counter (C#)

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.

> [!NOTE]
> 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.

## Sample Prerequisites

This sample will only run on macOS as it requires Xcode and an iOS simulator.

- Xcode: Any version should work with this sample (download Xcode at <https://developer.apple.com/xcode/>).
- iOS simulator 8.0 or greater.
- .NET sdk 6.0.100-alpha.1.20531.2 (Installation instructions in parent directory).

To install a specific version of the dotnet sdk, download the latest stable version of the dotnet-install script:

- Bash (Linux/macOS): <https://dot.net/v1/dotnet-install.sh>
- PowerShell (Windows): <https://dot.net/v1/dotnet-install.ps1>

Install version .NET version **6.0.100-alpha.1.20531.2**:

```bash
./dotnet-install.sh --version 6.0.100-alpha.1.20531.2
```

```powershell
./dotnet-install.ps1 -Version 6.0.100-alpha.1.20531.2
```

> [!NOTE]
> Modify `IosSimulator` under target `BuildAppBundle` from `iPhone 11` to your simulator's device name.

## Building the sample

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`.
7 changes: 7 additions & 0 deletions core/mono-samples/iOS/global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"sdk": {
"version": "6.0.100-alpha.1.20531.2",
"rollForward": "major",
"allowPrerelease": true
}
}
55 changes: 55 additions & 0 deletions core/mono-samples/iOS/iOSSampleApp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

public static class iOSSampleApp
{
// Defined in main.m
[DllImport("__Internal")]
private extern static void ios_set_text(string value);

[DllImport("__Internal")]
private extern static void ios_greet_name(string value);

[DllImport("__Internal")]
private extern static void ios_register_counter_increment(Action action);

[DllImport("__Internal")]
private extern static void ios_register_name_greet(Action<string> action);

private static int counter = 1;

// Called by native code, see main.m
private static void IncrementCounter()
{
ios_set_text($"Clicked {counter++} times!");
}

private static void GreetName(string name)
{
ios_greet_name(name);
}

public static async Task Main(string[] args)
{
// Register a managed callback (will be called by UIButton, see main.m)
// Also, keep the handler alive so GC won't collect it.
ios_register_counter_increment(IncrementCounter);
ios_register_name_greet(GreetName);

const string msg = "Hello World!";
for (int i = 0; i < msg.Length; i++)
{
// a kind of an animation
ios_set_text(msg.Substring(0, i + 1));
await Task.Delay(100);
}

Console.WriteLine("Done!");
await Task.Delay(-1);
}
}
57 changes: 57 additions & 0 deletions core/mono-samples/iOS/iOSSampleApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetArchitecture>x64</TargetArchitecture>
<RuntimeIdentifier>ios-$(TargetArchitecture)</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<PublishTrimmed>True</PublishTrimmed>
<TrimMode>link</TrimMode>
<Configuration>Release</Configuration>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Runtime.iOS.Sample.Mono" Version="6.0.0-*" GeneratePathProperty="true" />
</ItemGroup>

<UsingTask TaskName="AppleAppBuilderTask"
AssemblyFile="$(PkgMicrosoft_NET_Runtime_iOS_Sample_Mono)\tools\net6.0\AppleAppBuilder.dll" />

<Target Name="BuildAppBundle" AfterTargets="Publish">
<PropertyGroup>
<AppDir>$(MSBuildThisFileDirectory)$(PublishDir)</AppDir>
<IosSimulator Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'x86'">iPhone 11</IosSimulator>
<Optimized Condition="'$(Configuration)' == 'Release'">True</Optimized>
</PropertyGroup>

<ItemGroup>
<BundleAssemblies Include="$(AppDir)\*.dll" />
</ItemGroup>

<AppleAppBuilderTask
ProjectName="HelloiOS"
AppDir="$(AppDir)"
MonoRuntimeHeaders="%(ResolvedRuntimePack.PackageDirectory)\runtimes\$(RuntimeIdentifier)\native\include\mono-2.0"
MainLibraryFileName="$(MSBuildThisFileName).dll"
Assemblies="@(BundleAssemblies)"
OutputDirectory="$(AppDir)\app"
Optimized="$(Optimized)"
Arch="$(TargetArchitecture)"
BuildAppBundle="True"
GenerateXcodeProject="True"
NativeMainSource="$(MSBuildThisFileDirectory)main.m">
<Output TaskParameter="AppBundlePath" PropertyName="AppBundlePath" />
<Output TaskParameter="XcodeProjectPath" PropertyName="XcodeProjectPath" />
</AppleAppBuilderTask>

<Message Importance="High" Text="Xcode: $(XcodeProjectPath)" />
<Message Importance="High" Text="App: $(AppBundlePath)" />
<Message Importance="High" Text="Restarting device" />
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl shutdown &quot;$(IosSimulator)&quot;" ContinueOnError="WarnAndContinue" />
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl boot &quot;$(IosSimulator)&quot;" />
<Exec Condition="'$(IosSimulator)' != ''" Command="open -a Simulator" />
<Message Importance="High" Text="Installing application" />
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl install &quot;$(IosSimulator)&quot; $(AppBundlePath)" />
<Message Importance="High" Text="Launching application" />
<Exec Condition="'$(IosSimulator)' != ''" Command="xcrun simctl launch --console booted net.dot.HelloiOS" />
</Target>
</Project>
Loading