diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index 31ffddc20f3e..423f6a828258 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -10,6 +10,7 @@
+
@@ -696,8 +697,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_FrameworksFromAppExtensions Update="@(_FrameworksFromAppExtensions)">
+ $(_RelativePublishDir)$(_AppBundleFrameworksDir)\%(Filename)%(Extension).framework
+
+
+
- <_DirectoriesToPublish Include="@(_FilteredFrameworkToPublish)" />
+ <_DirectoriesToPublish Include="@(_FrameworksFromAppExtensions)" Condition="'$(IsAppExtension)' != 'true'" />
+ <_DirectoriesToPublish Include="@(_FilteredFrameworkToPublishWithFullPath)" Condition="'$(IsAppExtension)' != 'true'" />
@@ -967,6 +1009,13 @@
<_RuntimeConfigurationFile>runtimeconfig.bin
+
+
+ <_CustomLinkFlags Include="-rpath" />
+ <_CustomLinkFlags Include="@executable_path/../../Frameworks" Condition="'$(_PlatformName)' == 'iOS' Or '$(_PlatformName)' == 'tvOS'" />
+ <_CustomLinkFlags Include="@executable_path/../../../../Frameworks" Condition="'$(_PlatformName)' == 'macOS' Or '$(_PlatformName)' == 'MacCatalyst'" />
+
+
<_MonoLibrary
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/GetFullPaths.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/GetFullPaths.cs
new file mode 100644
index 000000000000..000b66f2c08a
--- /dev/null
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/GetFullPaths.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+using Xamarin.MacDev.Tasks;
+using Xamarin.Messaging.Build.Client;
+
+#nullable enable
+
+namespace Xamarin.MacDev.Tasks {
+ public class GetFullPaths : XamarinTask, ICancelableTask, ITaskCallback {
+ [Required]
+ public ITaskItem [] Items { get; set; } = Array.Empty ();
+
+ public string [] Metadata { get; set; } = Array.Empty ();
+
+ [Output]
+ public ITaskItem [] Output { get; set; } = Array.Empty ();
+
+ public override bool Execute ()
+ {
+ if (ShouldExecuteRemotely ())
+ return new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result;
+
+ return ExecuteLocally ();
+ }
+
+ public void Cancel ()
+ {
+ if (ShouldExecuteRemotely ())
+ BuildConnection.CancelAsync (BuildEngine4).Wait ();
+ }
+
+ bool ExecuteLocally ()
+ {
+ var rv = new List ();
+
+ foreach (var item in Items) {
+ var identity = item.ItemSpec;
+ if (Metadata.Length == 0 || Array.IndexOf (Metadata, "Identity") >= 0)
+ identity = Path.GetFullPath (identity);
+ var newItem = new TaskItem (identity);
+ item.CopyMetadataTo (newItem);
+ foreach (var md in Metadata) {
+ if (string.IsNullOrEmpty (md))
+ continue;
+ if (md == "Identity")
+ continue;
+ newItem.SetMetadata (md, Path.GetFullPath (newItem.GetMetadata (md)));
+ }
+ rv.Add (newItem);
+ }
+
+ Output = rv.ToArray ();
+
+ return !Log.HasLoggedErrors;
+ }
+
+ public bool ShouldCopyToBuildServer (ITaskItem item) => true;
+
+ public bool ShouldCreateOutputFile (ITaskItem item) => false;
+
+ public IEnumerable GetAdditionalItemsToBeCopied () => Enumerable.Empty ();
+ }
+}
diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
index 55994d67599b..de283376ed88 100644
--- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets
+++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
@@ -399,6 +399,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
+
@@ -2095,14 +2096,14 @@ Copyright (C) 2018 Microsoft. All rights reserved.
- <_CodesignBundle Include="@(_CodesignAppExtensionBundle->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)/%(Identity)')" />
+ <_CodesignBundle Include="@(_CodesignAppExtensionBundle->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)%(Identity)')" />
- <_CodesignItems Include="@(_CodesignAppExtensionItem->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)/%(Identity)')" />
+ <_CodesignItems Include="@(_CodesignAppExtensionItem->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)%(Identity)')" />
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/AppDelegate.cs b/tests/dotnet/ExtensionConsumerWithFrameworks/AppDelegate.cs
new file mode 100644
index 000000000000..46fb86ae5d03
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/AppDelegate.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Runtime.InteropServices;
+
+using Foundation;
+
+namespace MySimpleApp {
+ public class Program {
+ [DllImport ("__Internal")]
+ static extern int getUnknownE ();
+ [DllImport ("__Internal")]
+ static extern int getSomewhatUnknownD ();
+
+ static int Main (string [] args)
+ {
+ GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly
+
+ Console.WriteLine (getUnknownE ());
+ Console.WriteLine (getSomewhatUnknownD ());
+ Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));
+
+ return args.Length;
+ }
+ }
+}
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/Makefile b/tests/dotnet/ExtensionConsumerWithFrameworks/Makefile
new file mode 100644
index 000000000000..6affa45ff122
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/Makefile
@@ -0,0 +1,2 @@
+TOP=../../..
+include $(TOP)/tests/common/shared-dotnet-test.mk
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/ExtensionConsumer.sln b/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/ExtensionConsumer.sln
new file mode 100644
index 000000000000..41d43127d1bb
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/ExtensionConsumer.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySimpleApp", "MySimpleApp.csproj", "{23664512-6B06-4135-9A94-C012BDA93CB1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "..\..\ExtensionProject\iOS\ExtensionProject.csproj", "{8A72DB8F-4C30-4462-9F7A-6095E41D5D46}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {23664512-6B06-4135-9A94-C012BDA93CB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {23664512-6B06-4135-9A94-C012BDA93CB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {23664512-6B06-4135-9A94-C012BDA93CB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {23664512-6B06-4135-9A94-C012BDA93CB1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8A72DB8F-4C30-4462-9F7A-6095E41D5D46}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/ExtensionConsumerWithFrameworks.csproj b/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/ExtensionConsumerWithFrameworks.csproj
new file mode 100644
index 000000000000..86d408734aa8
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/ExtensionConsumerWithFrameworks.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-ios
+
+
+
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/Makefile b/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/Makefile
new file mode 100644
index 000000000000..110d078f4577
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/iOS/Makefile
@@ -0,0 +1 @@
+include ../shared.mk
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/ExtensionConsumer.sln b/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/ExtensionConsumer.sln
new file mode 100644
index 000000000000..d3caa485a413
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/ExtensionConsumer.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySimpleApp", "MySimpleApp.csproj", "{B7C29D40-0079-416C-8507-FE9EE82FBD4F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "..\..\ExtensionProject\macOS\ExtensionProject.csproj", "{C32EB68F-1FF7-42DE-ABD8-C0151497595A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B7C29D40-0079-416C-8507-FE9EE82FBD4F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C32EB68F-1FF7-42DE-ABD8-C0151497595A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/ExtensionConsumerWithFrameworks.csproj b/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/ExtensionConsumerWithFrameworks.csproj
new file mode 100644
index 000000000000..a77287b9ba00
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/ExtensionConsumerWithFrameworks.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-macos
+
+
+
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/Makefile b/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/Makefile
new file mode 100644
index 000000000000..110d078f4577
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/macOS/Makefile
@@ -0,0 +1 @@
+include ../shared.mk
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/shared.csproj b/tests/dotnet/ExtensionConsumerWithFrameworks/shared.csproj
new file mode 100644
index 000000000000..6d9e86482701
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/shared.csproj
@@ -0,0 +1,27 @@
+
+
+
+ Exe
+
+ ExtensionConsumerWithFramework
+ com.xamarin.extensionconsumerwithframework
+ $(MSBuildThisFileDirectory)/../..
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/shared.mk b/tests/dotnet/ExtensionConsumerWithFrameworks/shared.mk
new file mode 100644
index 000000000000..f555cad4e805
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/shared.mk
@@ -0,0 +1,2 @@
+TOP=../../../..
+include $(TOP)/tests/common/shared-dotnet.mk
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/ExtensionConsumer.sln b/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/ExtensionConsumer.sln
new file mode 100644
index 000000000000..0ace9b566748
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/ExtensionConsumer.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySimpleApp", "MySimpleApp.csproj", "{D8448FDC-1002-432B-A3A7-CCFCB833F292}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "..\..\ExtensionProject\tvOS\ExtensionProject.csproj", "{CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D8448FDC-1002-432B-A3A7-CCFCB833F292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D8448FDC-1002-432B-A3A7-CCFCB833F292}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D8448FDC-1002-432B-A3A7-CCFCB833F292}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D8448FDC-1002-432B-A3A7-CCFCB833F292}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CD69BE1D-FF1B-4B6A-AB6E-5259E65B515E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/ExtensionConsumerWithFrameworks.csproj b/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/ExtensionConsumerWithFrameworks.csproj
new file mode 100644
index 000000000000..bd487ddcd88d
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/ExtensionConsumerWithFrameworks.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-tvos
+
+
+
diff --git a/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/Makefile b/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/Makefile
new file mode 100644
index 000000000000..110d078f4577
--- /dev/null
+++ b/tests/dotnet/ExtensionConsumerWithFrameworks/tvOS/Makefile
@@ -0,0 +1 @@
+include ../shared.mk
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/Makefile b/tests/dotnet/ExtensionProjectWithFrameworks/Makefile
new file mode 100644
index 000000000000..6affa45ff122
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/Makefile
@@ -0,0 +1,2 @@
+TOP=../../..
+include $(TOP)/tests/common/shared-dotnet-test.mk
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Entitlements.plist b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Entitlements.plist
new file mode 100644
index 000000000000..9ae599370b42
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ExtensionProject.sln b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ExtensionProject.sln
new file mode 100644
index 000000000000..903746a576aa
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ExtensionProject.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "ExtensionProject.csproj", "{6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6938058D-AE12-4CF8-A3DD-E27BCCEF1E6E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ExtensionProjectWithFrameworks.csproj b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ExtensionProjectWithFrameworks.csproj
new file mode 100644
index 000000000000..86d408734aa8
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ExtensionProjectWithFrameworks.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-ios
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Info.plist b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Info.plist
new file mode 100644
index 000000000000..64639a6bc4f9
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ MyShareExtension
+ CFBundleIdentifier
+ com.xamarin.MyMasterDetailApp.MyShareExtension
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ com.xamarin.MyShareExtension
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ NSExtension
+
+ NSExtensionAttributes
+
+ NSExtensionActivationRule
+ TRUEPREDICATE
+ NSExtensionPointName
+ com.apple.share-services
+ NSExtensionPointVersion
+ 1.0
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.share-services
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/MainInterface.storyboard b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/MainInterface.storyboard
new file mode 100644
index 000000000000..10d089e2a175
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/MainInterface.storyboard
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Makefile b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Makefile
new file mode 100644
index 000000000000..110d078f4577
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/Makefile
@@ -0,0 +1 @@
+include ../shared.mk
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ShareViewController.cs b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ShareViewController.cs
new file mode 100644
index 000000000000..08d46e5378c8
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ShareViewController.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Drawing;
+
+using Foundation;
+using Social;
+using UIKit;
+
+namespace MyShareExtension {
+ public partial class ShareViewController : SLComposeServiceViewController {
+ public ShareViewController (IntPtr handle) : base (handle)
+ {
+ }
+
+ public override bool IsContentValid ()
+ {
+ // Do validation of contentText and/or NSExtensionContext attachments here
+ return true;
+ }
+
+ public override void DidSelectPost ()
+ {
+ // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
+
+ // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
+ ExtensionContext.CompleteRequest (null, null);
+ }
+
+ public override SLComposeSheetConfigurationItem [] GetConfigurationItems ()
+ {
+ // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
+ return new SLComposeSheetConfigurationItem [0];
+ }
+ }
+}
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ShareViewController.designer.cs b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ShareViewController.designer.cs
new file mode 100644
index 000000000000..ac1e6b1b25f8
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/iOS/ShareViewController.designer.cs
@@ -0,0 +1,18 @@
+//
+// This file has been generated automatically by MonoDevelop to store outlets and
+// actions made in the Xcode designer. If it is removed, they will be lost.
+// Manual changes to this file may not be handled correctly.
+//
+
+using Foundation;
+
+namespace MyShareExtension
+{
+ [Register ("ShareViewController")]
+ partial class ShareViewController
+ {
+ void ReleaseDesignerOutlets ()
+ {
+ }
+ }
+}
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Entitlements.plist b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Entitlements.plist
new file mode 100644
index 000000000000..ffef54421f6d
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Entitlements.plist
@@ -0,0 +1,11 @@
+
+
+
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.files.user-selected.read-only
+
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ExtensionProject.sln b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ExtensionProject.sln
new file mode 100644
index 000000000000..d73c069da5cd
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ExtensionProject.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "ExtensionProject.csproj", "{448A63DB-EEA4-4F1B-AB62-144A978EB7ED}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {448A63DB-EEA4-4F1B-AB62-144A978EB7ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {448A63DB-EEA4-4F1B-AB62-144A978EB7ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {448A63DB-EEA4-4F1B-AB62-144A978EB7ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {448A63DB-EEA4-4F1B-AB62-144A978EB7ED}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ExtensionProjectWithFrameworks.csproj b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ExtensionProjectWithFrameworks.csproj
new file mode 100644
index 000000000000..9c2d837e8f91
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ExtensionProjectWithFrameworks.csproj
@@ -0,0 +1,8 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-macos
+ $(SourceDirectory)Entitlements.plist
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Info.plist b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Info.plist
new file mode 100644
index 000000000000..a8d7d34c1b2f
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ ShareExtension
+ CFBundleExecutable
+ ExtensionProjectWithFrameworks
+ CFBundleIdentifier
+ com.xamarin.ShareExtensionTest
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ NSExtension
+
+ NSExtensionAttributes
+
+ NSExtensionActivationRule
+ TRUEPREDICATE
+
+ NSExtensionPointIdentifier
+ com.apple.share-services
+ NSExtensionPrincipalClass
+ ShareViewController
+
+
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Makefile b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Makefile
new file mode 100644
index 000000000000..110d078f4577
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/Makefile
@@ -0,0 +1 @@
+include ../shared.mk
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.cs b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.cs
new file mode 100644
index 000000000000..95a23c5e0d77
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Drawing;
+
+using NotificationCenter;
+using Foundation;
+using Social;
+using AppKit;
+using System.Linq;
+
+namespace ShareExtensionTest {
+ public partial class ShareViewController : NSViewController {
+ public ShareViewController (IntPtr handle) : base (handle)
+ {
+ }
+
+ public override void LoadView ()
+ {
+ base.LoadView ();
+
+ NSExtensionItem item = ExtensionContext.InputItems.First ();
+ Console.WriteLine ("Attachments {0}", item);
+ }
+
+ partial void Cancel (Foundation.NSObject sender)
+ {
+ NSExtensionItem outputItem = new NSExtensionItem ();
+ var outputItems = new [] { outputItem };
+ ExtensionContext.CompleteRequest (outputItems, null);
+ }
+
+ partial void Send (Foundation.NSObject sender)
+ {
+ NSError cancelError = NSError.FromDomain (NSError.CocoaErrorDomain, 3072, null);
+ ExtensionContext.CancelRequest (cancelError);
+ }
+ }
+}
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.designer.cs b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.designer.cs
new file mode 100644
index 000000000000..6801a6932c4b
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.designer.cs
@@ -0,0 +1,24 @@
+//
+// This file has been generated automatically by MonoDevelop to store outlets and
+// actions made in the Xcode designer. If it is removed, they will be lost.
+// Manual changes to this file may not be handled correctly.
+//
+
+using Foundation;
+
+namespace ShareExtensionTest
+{
+ [Register ("ShareViewController")]
+ partial class ShareViewController
+ {
+ [Action ("Cancel:")]
+ partial void Cancel (Foundation.NSObject sender);
+
+ [Action ("Send:")]
+ partial void Send (Foundation.NSObject sender);
+
+ void ReleaseDesignerOutlets ()
+ {
+ }
+ }
+}
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.xib b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.xib
new file mode 100644
index 000000000000..592a458e43a2
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/macOS/ShareViewController.xib
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/shared.csproj b/tests/dotnet/ExtensionProjectWithFrameworks/shared.csproj
new file mode 100644
index 000000000000..a125e1e30a06
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/shared.csproj
@@ -0,0 +1,20 @@
+
+
+
+ true
+ $(MSBuildThisFileDirectory)/../..
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/shared.mk b/tests/dotnet/ExtensionProjectWithFrameworks/shared.mk
new file mode 100644
index 000000000000..f555cad4e805
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/shared.mk
@@ -0,0 +1,2 @@
+TOP=../../../..
+include $(TOP)/tests/common/shared-dotnet.mk
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Entitlements.plist b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Entitlements.plist
new file mode 100644
index 000000000000..9ae599370b42
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ExtensionProject.sln b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ExtensionProject.sln
new file mode 100644
index 000000000000..1c748954a656
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ExtensionProject.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionProject", "ExtensionProject.csproj", "{AE305EDB-9818-447B-9BBD-95562A6BCFB0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AE305EDB-9818-447B-9BBD-95562A6BCFB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE305EDB-9818-447B-9BBD-95562A6BCFB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE305EDB-9818-447B-9BBD-95562A6BCFB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE305EDB-9818-447B-9BBD-95562A6BCFB0}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ExtensionProjectWithFrameworks.csproj b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ExtensionProjectWithFrameworks.csproj
new file mode 100644
index 000000000000..bd487ddcd88d
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ExtensionProjectWithFrameworks.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-tvos
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Info.plist b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Info.plist
new file mode 100644
index 000000000000..92b6b6e6c14a
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ CFBundleDisplayName
+ MyTVServicesExtension
+ CFBundleName
+ MyTVServicesExtension
+ CFBundleIdentifier
+ com.xamarin.mytvapp.mytvservicesextension
+ CFBundleDevelopmentRegion
+ en
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ NSExtension
+
+ NSExtensionAttributes
+
+ TVExtensionProtocols
+
+ TVTopShelfProvider
+
+
+ NSExtensionPointIdentifier
+ com.apple.tv-services
+ NSExtensionPrincipalClass
+ ServiceProvider
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+
+
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Makefile b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Makefile
new file mode 100644
index 000000000000..110d078f4577
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Makefile
@@ -0,0 +1 @@
+include ../shared.mk
diff --git a/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ServiceProvider.cs b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ServiceProvider.cs
new file mode 100644
index 000000000000..c845047d0816
--- /dev/null
+++ b/tests/dotnet/ExtensionProjectWithFrameworks/tvOS/ServiceProvider.cs
@@ -0,0 +1,27 @@
+using System;
+using Foundation;
+using TVServices;
+
+namespace MyTVServicesExtension {
+ [Register ("ServiceProvider")]
+ public class ServiceProvider : NSObject, ITVTopShelfProvider {
+ protected ServiceProvider (IntPtr handle) : base (handle)
+ {
+ // Note: this .ctor should not contain any initialization logic.
+ }
+
+ public TVContentItem [] TopShelfItems {
+ [Export ("topShelfItems")]
+ get {
+ return new TVContentItem [] { new TVContentItem (new TVContentIdentifier ("identifier", null)) { Title = "title" } };
+ }
+ }
+
+ public TVTopShelfContentStyle TopShelfStyle {
+ [Export ("topShelfStyle")]
+ get {
+ return TVTopShelfContentStyle.Inset;
+ }
+ }
+ }
+}
diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs
index cf28e07598cf..32473c67b15f 100644
--- a/tests/dotnet/UnitTests/ProjectTest.cs
+++ b/tests/dotnet/UnitTests/ProjectTest.cs
@@ -976,6 +976,42 @@ public void BuildProjectsWithExtensions (ApplePlatform platform)
Assert.AreNotEqual (0, configFiles.Length, "runtimeconfig.json file does not exist");
}
+ [TestCase (ApplePlatform.iOS)]
+ [TestCase (ApplePlatform.TVOS)]
+ [TestCase (ApplePlatform.MacOSX)]
+ // [TestCase ("MacCatalyst", "")] - No extension support yet
+ public void BuildProjectsWithExtensionsAndFrameworks (ApplePlatform platform)
+ {
+ Configuration.IgnoreIfIgnoredPlatform (platform);
+ var runtimeIdentifiers = GetDefaultRuntimeIdentifier (platform);
+ var consumingProjectDir = GetProjectPath ("ExtensionConsumerWithFrameworks", runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath);
+ var extensionProjectDir = GetProjectPath ("ExtensionProjectWithFrameworks", platform: platform);
+
+ Clean (extensionProjectDir);
+ Clean (consumingProjectDir);
+
+ DotNet.AssertBuild (consumingProjectDir, verbosity);
+
+ var extensionPath = Path.Combine (Path.GetDirectoryName (consumingProjectDir)!, "bin", "Debug", platform.ToFramework (), GetDefaultRuntimeIdentifier (platform), "ExtensionConsumerWithFrameworks.app", GetPlugInsRelativePath (platform), "ExtensionProjectWithFrameworks.appex");
+ Assert.That (Directory.Exists (extensionPath), $"App extension directory does not exist: {extensionPath}");
+ var extensionFrameworksPath = Path.Combine (extensionPath, GetFrameworksRelativePath (platform));
+ Assert.IsFalse (Directory.Exists (extensionFrameworksPath), $"App extension framework directory exists when it shouldn't: {extensionFrameworksPath}");
+
+ var pathToSearch = Path.Combine (Path.GetDirectoryName (consumingProjectDir)!, "bin", "Debug");
+ var configFiles = Directory.GetFiles (pathToSearch, "*.runtimeconfig.*", SearchOption.AllDirectories);
+ Assert.AreNotEqual (0, configFiles.Length, "runtimeconfig.json file does not exist");
+
+ var appFrameworksPath = Path.Combine (appPath, GetFrameworksRelativePath (platform));
+ Assert.That (Directory.Exists (appFrameworksPath), $"App Frameworks directory does not exist: {appFrameworksPath}");
+
+ Assert.That (File.Exists (Path.Combine (appFrameworksPath, "SomewhatUnknownD.framework", "SomewhatUnknownD")), "SomewhatUnknownD");
+ Assert.That (File.Exists (Path.Combine (appFrameworksPath, "UnknownD.framework", "UnknownD")), "UnknownD");
+ Assert.That (File.Exists (Path.Combine (appFrameworksPath, "UnknownE.framework", "UnknownE")), "UnknownE");
+
+ var appExecutable = GetNativeExecutable (platform, appPath);
+ ExecuteWithMagicWordAndAssert (platform, runtimeIdentifiers, appExecutable);
+ }
+
[TestCase (ApplePlatform.iOS, "iossimulator-x64;iossimulator-arm64")]
[TestCase (ApplePlatform.TVOS, "tvossimulator-x64")]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-x64")]
diff --git a/tests/dotnet/UnitTests/TestBaseClass.cs b/tests/dotnet/UnitTests/TestBaseClass.cs
index ff589f6a57f3..b672071bac2d 100644
--- a/tests/dotnet/UnitTests/TestBaseClass.cs
+++ b/tests/dotnet/UnitTests/TestBaseClass.cs
@@ -124,6 +124,20 @@ protected string GetPlugInsRelativePath (ApplePlatform platform)
}
}
+ protected string GetFrameworksRelativePath (ApplePlatform platform)
+ {
+ switch (platform) {
+ case ApplePlatform.iOS:
+ case ApplePlatform.TVOS:
+ return "Frameworks";
+ case ApplePlatform.MacCatalyst:
+ case ApplePlatform.MacOSX:
+ return Path.Combine ("Contents", "Frameworks");
+ default:
+ throw new ArgumentOutOfRangeException ($"Unknown platform: {platform}");
+ }
+ }
+
protected void Clean (string project_path)
{
var dirs = Directory.GetDirectories (Path.GetDirectoryName (project_path)!, "*", SearchOption.AllDirectories);