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

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 https://github.com/xamarin/xamarin-macios/issues/17876.
Fixes https://github.com/xamarin/xamarin-macios/issues/17679.
This commit is contained in:
Rolf Bjarne Kvinge 2023-09-11 09:52:54 +02:00 коммит произвёл GitHub
Родитель b44b57e59d
Коммит de762d67cc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
43 изменённых файлов: 837 добавлений и 3 удалений

Просмотреть файл

@ -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>
<_DirectoriesToPublish Include="@(_FilteredFrameworkToPublish)" />
<_FrameworksFromAppExtensions Update="@(_FrameworksFromAppExtensions)">
<TargetDirectory>$(_RelativePublishDir)$(_AppBundleFrameworksDir)\%(Filename)%(Extension).framework</TargetDirectory>
</_FrameworksFromAppExtensions>
</ItemGroup>
<ItemGroup>
<_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

Просмотреть файл

@ -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<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;
}
public bool ShouldCopyToBuildServer (ITaskItem item) => true;
public bool ShouldCreateOutputFile (ITaskItem item) => false;
public IEnumerable<ITaskItem> GetAdditionalItemsToBeCopied () => Enumerable.Empty<ITaskItem> ();
}
}

Просмотреть файл

@ -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>
@ -2092,14 +2093,14 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<Output TaskParameter="Items" ItemName="_CodesignAppExtensionBundle" />
</ReadItemsFromFile>
<ItemGroup>
<_CodesignBundle Include="@(_CodesignAppExtensionBundle->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)/%(Identity)')" />
<_CodesignBundle Include="@(_CodesignAppExtensionBundle->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)%(Identity)')" />
</ItemGroup>
<!-- Get items to sign from app extensions -->
<ReadItemsFromFile File="@(_ResolvedAppExtensionReferences->'%(Identity)\..\codesign.items')" Condition="Exists('%(Identity)\..\codesign.items')">
<Output TaskParameter="Items" ItemName="_CodesignAppExtensionItem" />
</ReadItemsFromFile>
<ItemGroup>
<_CodesignItems Include="@(_CodesignAppExtensionItem->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)/%(Identity)')" />
<_CodesignItems Include="@(_CodesignAppExtensionItem->'$(_AppBundleName)$(AppBundleExtension)/$(_AppPlugInsRelativePath)%(Identity)')" />
</ItemGroup>
<!-- Get app bundles to sign from watch apps -->

Просмотреть файл

@ -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;
}
}
}

Просмотреть файл

@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1,2 @@
TOP=../../../..
include $(TOP)/tests/common/shared-dotnet.mk

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk

Просмотреть файл

@ -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>

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -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];
}
}
}

Просмотреть файл

@ -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 ()
{
}
}
}

Просмотреть файл

@ -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>

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>ExtensionProjectWithFrameworks</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>

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -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);
}
}
}

Просмотреть файл

@ -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 ()
{
}
}
}

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1,2 @@
TOP=../../../..
include $(TOP)/tests/common/shared-dotnet.mk

Просмотреть файл

@ -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>

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -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;
}
}
}
}

Просмотреть файл

@ -976,6 +976,42 @@ namespace Xamarin.Tests {
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")]

Просмотреть файл

@ -124,6 +124,20 @@ namespace Xamarin.Tests {
}
}
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);