diff --git a/src/libraries/IntegrationTests/Directory.Build.props b/src/libraries/IntegrationTests/Directory.Build.props new file mode 100644 index 00000000000000..5f191efe27c2e9 --- /dev/null +++ b/src/libraries/IntegrationTests/Directory.Build.props @@ -0,0 +1,3 @@ + + + diff --git a/src/libraries/IntegrationTests/tests/iOS/Program.cs b/src/libraries/IntegrationTests/tests/iOS/Program.cs new file mode 100644 index 00000000000000..9769ded207e150 --- /dev/null +++ b/src/libraries/IntegrationTests/tests/iOS/Program.cs @@ -0,0 +1,53 @@ +// 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; + +// it's not part of the BCL but runtime needs it for native-to-managed callbacks in AOT +// To be replaced with NativeCallableAttribute +public class MonoPInvokeCallbackAttribute : Attribute +{ + public MonoPInvokeCallbackAttribute(Type delegateType) { } +} + +public static class Program +{ + // Defined in main.m + [DllImport("__Internal")] + private extern static void ios_set_text(string value); + + [DllImport("__Internal")] + private extern static void ios_register_button_click(Action action); + + private static Action buttonClickHandler = null; + + private static int counter = 0; + + // Called by native code, see main.m + [MonoPInvokeCallback(typeof(Action))] + private static void OnButtonClick() + { + ios_set_text("OnButtonClick! #" + counter++); + } + + 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_button_click(buttonClickHandler = OnButtonClick); + + const string msg = "Hello World!\n.NET 5.0"; + 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); + } +} diff --git a/src/libraries/IntegrationTests/tests/iOS/iOS.Simulator.Aot.Integration.Tests.csproj b/src/libraries/IntegrationTests/tests/iOS/iOS.Simulator.Aot.Integration.Tests.csproj new file mode 100644 index 00000000000000..0f45ace47fc9bb --- /dev/null +++ b/src/libraries/IntegrationTests/tests/iOS/iOS.Simulator.Aot.Integration.Tests.csproj @@ -0,0 +1,88 @@ + + + Exe + bin + Portable + $(NetCoreAppCurrent) + iOS + $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)\$(Configuration)\runtimes\ios-$(TargetArchitecture)\ + false + ios-$(TargetArchitecture) + true + link + True + true + false + + + + + + + $(ArtifactsBinDir)microsoft.netcore.app.runtime.ios-$(TargetArchitecture)\$(Configuration) + + + + + + + + + + + + + $(MSBuildThisFileDirectory)$(PublishDir)\app + iPhone 11 + + + + + + + + @(MonoAOTCompilerDefaultAotArguments, ';') + @(MonoAOTCompilerDefaultProcessArguments, ';') + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/IntegrationTests/tests/iOS/main.m b/src/libraries/IntegrationTests/tests/iOS/main.m new file mode 100644 index 00000000000000..0ab407e8398682 --- /dev/null +++ b/src/libraries/IntegrationTests/tests/iOS/main.m @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#import +#import "runtime.h" + +@interface ViewController : UIViewController +@end + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) ViewController *controller; +@end + +@implementation AppDelegate +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.controller = [[ViewController alloc] initWithNibName:nil bundle:nil]; + self.window.rootViewController = self.controller; + [self.window makeKeyAndVisible]; + return YES; +} +@end + +UILabel *label; +void (*clickHandlerPtr)(void); + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + label = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + label.textColor = [UIColor greenColor]; + label.font = [UIFont boldSystemFontOfSize: 30]; + label.numberOfLines = 2; + label.textAlignment = NSTextAlignmentCenter; + [self.view addSubview:label]; + + UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoDark]; + [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; + [button setFrame:CGRectMake(50, 300, 200, 50)]; + [button setTitle:@"Click me" forState:UIControlStateNormal]; + [button setExclusiveTouch:YES]; + [self.view addSubview:button]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + mono_ios_runtime_init (); + }); +} +-(void) buttonClicked:(UIButton*)sender +{ + if (clickHandlerPtr) + clickHandlerPtr(); +} + +@end + +// called from C# sample +void +ios_register_button_click (void* ptr) +{ + clickHandlerPtr = ptr; +} + +// called from C# sample +void +ios_set_text (const char* value) +{ + NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; + dispatch_async(dispatch_get_main_queue(), ^{ + label.text = nsstr; + }); +} + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 511f7f68fe0020..f144efad5e2e41 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -151,6 +151,10 @@ + + + +