Skip to content
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

[dotnet] Point app extensions to any frameworks in the root app bundle. Fixes #17876. #18913

Merged
Changes from 1 commit
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
Next Next commit
[dotnet] Point app extensions to any frameworks in the root app bundle.
Fixes #17876.

Put any frameworks in app extensions in the Frameworks directory in the
containing app bundle. This saves a lot of space if the same framework is used
in both an app extension and the containing project (or multiple app
extensions).

Fixes #17876.
Fixes #17679.
rolfbjarne committed Sep 1, 2023
commit ab6e20afa9a4625a5084fc11ca99239fc3358db5
51 changes: 50 additions & 1 deletion dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
<UsingTask TaskName="Xamarin.MacDev.Tasks.CompileNativeCode" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.FilterStaticFrameworks" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.FindAotCompiler" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.GetFullPaths" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.InstallNameTool" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.LinkNativeCode" AssemblyFile="$(_XamarinTaskAssembly)" />
<UsingTask TaskName="Xamarin.MacDev.Tasks.MergeAppBundles" AssemblyFile="$(_XamarinTaskAssembly)" />
@@ -696,8 +697,49 @@
<Output TaskParameter="FrameworkToPublish" ItemName="_FilteredFrameworkToPublish" />
</FilterStaticFrameworks>

<!--
We need to use the full path to the framework for frameworks that
come from app extensions (since any relative paths from the app
extension projects won't be correct once loaded into the
containing project), so compute that. However, also do this for
app projects, so that we can properly deduplicate frameworks that
come from both extensions and the main app project.
-->
<GetFullPaths
Condition="'$(IsMacEnabled)' == 'true'"
SessionId="$(BuildSessionId)"
Items="@(_FilteredFrameworkToPublish)"
Metadata="Identity;SourceDirectory"
>
<Output TaskParameter="Output" ItemName="_FilteredFrameworkToPublishWithFullPath" />
</GetFullPaths>

<!-- If we're an app extension, store the list of all the frameworks to disk (and don't publish any of them to the appex) -->
<!-- Note that app extensions may be nested, so we first check if we have any app extensions with frameworks, read those, then store the full list to disk if we're an app extension, so the containing app project sees everything -->
<ReadItemsFromFile File="@(_ResolvedAppExtensionReferences->'%(Identity)\..\native-frameworks.items')" Condition="Exists('%(Identity)\..\native-frameworks.items')">
<Output TaskParameter="Items" ItemName="_FrameworksFromAppExtensions" />
</ReadItemsFromFile>

<WriteItemsToFile
Condition="'$(IsAppExtension)' == 'true'"
Items="@(_FilteredFrameworkToPublishWithFullPath);@(_FrameworksFromAppExtensions)"
ItemName="_FrameworksFromAppExtensions"
File="$(DeviceSpecificOutputPath)\native-frameworks.items"
IncludeMetadata="true"
Overwrite="true"
/>

<ItemGroup>
<_FrameworksFromAppExtensions Update="@(_FrameworksFromAppExtensions)">
<TargetDirectory>$(_RelativePublishDir)$(_AppBundleFrameworksDir)\%(Filename)%(Extension).framework</TargetDirectory>
</_FrameworksFromAppExtensions>
</ItemGroup>

<ItemGroup>
<_DirectoriesToPublish Include="@(_FilteredFrameworkToPublish)" />
<_DirectoriesToPublish Include="@(_FrameworksFromAppExtensions)" Condition="'$(IsAppExtension)' != 'true'" />
<_DirectoriesToPublish Include="@(_FilteredFrameworkToPublishWithFullPath)" Condition="'$(IsAppExtension)' != 'true'" />
</ItemGroup>
</Target>

@@ -967,6 +1009,13 @@
<_RuntimeConfigurationFile>runtimeconfig.bin</_RuntimeConfigurationFile>
</PropertyGroup>

<!-- Not sure about how to handle nested app extensions here, but if it ever becomes a problem we can look into it (I believe only watch extensions can have embedded extensions at this point, and we don't support watchOS on .NET anyways) -->
<ItemGroup Condition="'$(IsAppExtension)' == 'true'">
<_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'" />
</ItemGroup>

<ItemGroup>
<!-- Select the native libraries from mono we need to link with and potentially copy into the app -->
<_MonoLibrary
62 changes: 62 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/GetFullPaths.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;

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 {
[Required]
public ITaskItem[] Items { get; set; } = Array.Empty<ITaskItem> ();

public string[] Metadata { get; set; } = Array.Empty<string> ();

[Output]
public ITaskItem[] Output { get; set; } = Array.Empty<ITaskItem> ();

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<ITaskItem> ();

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;
}
}
}
1 change: 1 addition & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
@@ -399,6 +399,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.

<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)codesign.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)codesign-bundle.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="$(DeviceSpecificOutputPath)native-frameworks.items" />
<Delete SessionId="$(BuildSessionId)" Condition="'$(IsMacEnabled)' == 'true'" Files="@(_IpaPackageFile)" />
</Target>

24 changes: 24 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/AppDelegate.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
2 changes: 2 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
27 changes: 27 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>

<ApplicationTitle>ExtensionConsumerWithFramework</ApplicationTitle>
<ApplicationId>com.xamarin.extensionconsumerwithframework</ApplicationId>
<RootTestsDirectory Condition="'$(RootTestsDirectory)' == ''">$(MSBuildThisFileDirectory)/../..</RootTestsDirectory>
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\ExtensionProjectWithFrameworks\$(_PlatformName)\ExtensionProjectWithFrameworks.csproj">
<IsAppExtension>true</IsAppExtension>
</ProjectReference>

<!-- Both the extension and the consumer references UnknownE.framework -->
<None Include="$(RootTestsDirectory)/test-libraries/frameworks/.libs/$(RuntimeIdentifier)/UnknownE.framework" CopyToPublishDirectory="PreserveNewest" PublishFolderType="AppleFramework" />
<!-- Only the consumer references SomewhatUnknownD.framework -->
<None Include="$(RootTestsDirectory)/test-libraries/frameworks/.libs/$(RuntimeIdentifier)/SomewhatUnknownD.framework.zip" CopyToPublishDirectory="PreserveNewest" Link="Subfolder/SomewhatUnknownD.bin" PublishFolderType="CompressedAppleFramework" />
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions tests/dotnet/ExtensionConsumerWithFrameworks/shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../../..
include $(TOP)/tests/common/shared-dotnet.mk
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
2 changes: 2 additions & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
40 changes: 40 additions & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/iOS/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>MyShareExtension</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.MyMasterDetailApp.MyShareExtension</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>com.xamarin.MyShareExtension</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<string>TRUEPREDICATE</string>
<key>NSExtensionPointName</key>
<string>com.apple.share-services</string>
<key>NSExtensionPointVersion</key>
<string>1.0</string>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6150.1" systemVersion="13D65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="j1y-V4-xli">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6148" />
</dependencies>
<scenes>
<!--Share View Controller-->
<scene sceneID="ceB-am-kn3">
<objects>
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="8bI-gs-bmD" />
<viewControllerLayoutGuide type="bottom" id="d5i-Ba-RvD" />
</layoutGuides>
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
<rect key="frame" x="0.0" y="0.0" width="480" height="480" />
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" />
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite" />
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight" />
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder" />
</objects>
<point key="canvasLocation" x="539" y="97" />
</scene>
</scenes>
</document>
1 change: 1 addition & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/iOS/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -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];
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>

Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
<CodesignEntitlements>$(SourceDirectory)Entitlements.plist</CodesignEntitlements>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
40 changes: 40 additions & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/macOS/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>ShareExtension</string>
<key>CFBundleExecutable</key>
<string>ExtensionProject</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.ShareExtensionTest</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<string>TRUEPREDICATE</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
<key>NSExtensionPrincipalClass</key>
<string>ShareViewController</string>
</dict>

</dict>
</plist>

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx" />
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10116" />
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ShareViewController">
<connections>
<outlet property="view" destination="1" id="2" />
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder" />
<customObject id="-3" userLabel="Application" customClass="NSObject" />
<customView translatesAutoresizingMaskIntoConstraints="NO" id="1">
<rect key="frame" x="0.0" y="0.0" width="387" height="202" />
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1uM-r7-H1c">
<rect key="frame" x="301" y="3" width="82" height="32" />
<buttonCell key="cell" type="push" title="Send" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="2l4-PO-we5">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" />
<font key="font" metaFont="system" />
<string key="keyEquivalent">D</string>
<modifierMask key="keyEquivalentModifierMask" command="YES" />
</buttonCell>
<connections>
<action selector="Send:" target="-2" id="eEw-Je-X0B" />
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NVE-vN-dkz">
<rect key="frame" x="223" y="3" width="82" height="32" />
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="60" id="cP1-hK-9ZX" />
</constraints>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6Up-t3-mwm">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" />
<font key="font" metaFont="system" />
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="Cancel:" target="-2" id="AY8-gC-hec" />
</connections>
</button>
<textField verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aNc-0i-CWK">
<rect key="frame" x="138" y="171" width="111" height="16" />
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="My Service Title" id="0xp-rC-2gr">
<font key="font" metaFont="systemBold" />
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog" />
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog" />
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4M6-D5-WIf">
<rect key="frame" x="108" y="171" width="22" height="22" />
<constraints>
<constraint firstAttribute="width" constant="22" id="BOe-aZ-Njc" />
<constraint firstAttribute="height" constant="22" id="zLg-1a-wlZ" />
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="q3u-Am-ZIA" />
</imageView>
</subviews>
<constraints>
<constraint firstItem="1uM-r7-H1c" firstAttribute="leading" secondItem="NVE-vN-dkz" secondAttribute="trailing" constant="8" id="1UO-J1-LbJ" />
<constraint firstAttribute="bottom" secondItem="1uM-r7-H1c" secondAttribute="bottom" constant="10" id="4wH-De-nMF" />
<constraint firstAttribute="bottom" secondItem="NVE-vN-dkz" secondAttribute="bottom" constant="10" id="USG-Gg-of3" />
<constraint firstItem="1uM-r7-H1c" firstAttribute="leading" secondItem="NVE-vN-dkz" secondAttribute="trailing" constant="8" id="a8N-vS-Ew9" />
<constraint firstItem="aNc-0i-CWK" firstAttribute="centerY" secondItem="4M6-D5-WIf" secondAttribute="centerY" constant="2.5" id="ilP-G0-GVG" />
<constraint firstItem="NVE-vN-dkz" firstAttribute="width" secondItem="1uM-r7-H1c" secondAttribute="width" id="qPo-ky-Fcw" />
<constraint firstAttribute="trailing" secondItem="1uM-r7-H1c" secondAttribute="trailing" constant="10" id="qfT-cw-QQ2" />
<constraint firstAttribute="centerX" secondItem="aNc-0i-CWK" secondAttribute="centerX" id="uV3-Wn-RA3" />
<constraint firstItem="aNc-0i-CWK" firstAttribute="leading" secondItem="4M6-D5-WIf" secondAttribute="trailing" constant="10" id="vFR-5i-Dvo" />
<constraint firstItem="aNc-0i-CWK" firstAttribute="top" secondItem="1" secondAttribute="top" constant="15" id="vpR-tf-ebx" />
</constraints>
</customView>
</objects>
</document>
20 changes: 20 additions & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/shared.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<IsAppExtension>true</IsAppExtension>
<RootTestsDirectory Condition="'$(RootTestsDirectory)' == ''">$(MSBuildThisFileDirectory)/../..</RootTestsDirectory>
</PropertyGroup>

<Import Project="../../common/shared-dotnet.csproj" />

<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>

<ItemGroup>
<!-- Only the extension references UnknownD.framework -->
<None Include="$(RootTestsDirectory)/test-libraries/frameworks/.libs/$(RuntimeIdentifier)/UnknownD.framework.zip" CopyToPublishDirectory="PreserveNewest" PublishFolderType="CompressedAppleFramework" />
<!-- Both the extension and the consumer references UnknownE.framework -->
<None Include="$(RootTestsDirectory)/test-libraries/frameworks/.libs/$(RuntimeIdentifier)/UnknownE.framework" CopyToPublishDirectory="PreserveNewest" PublishFolderType="AppleFramework" />
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/shared.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TOP=../../../..
include $(TOP)/tests/common/shared-dotnet.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>
40 changes: 40 additions & 0 deletions tests/dotnet/ExtensionProjectWithFrameworks/tvOS/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>MyTVServicesExtension</string>
<key>CFBundleName</key>
<string>MyTVServicesExtension</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.mytvapp.mytvservicesextension</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>TVExtensionProtocols</key>
<array>
<string>TVTopShelfProvider</string>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.tv-services</string>
<key>NSExtensionPrincipalClass</key>
<string>ServiceProvider</string>
</dict>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../shared.mk
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
}
35 changes: 35 additions & 0 deletions tests/dotnet/UnitTests/ProjectTest.cs
Original file line number Diff line number Diff line change
@@ -976,6 +976,41 @@ 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 consumingProjectDir = GetProjectPath ("ExtensionConsumerWithFrameworks", 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")]
14 changes: 14 additions & 0 deletions tests/dotnet/UnitTests/TestBaseClass.cs
Original file line number Diff line number Diff line change
@@ -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);