Windows 공유 시트를 사용하면 앱을 통해 콘텐츠(다른 앱에서 공유)를 받을 수 있습니다. 이 가이드에서는 앱을 공유 대상으로 등록하고 MSIX(패키지 앱), PWA(프로그레시브 Web Apps) 및 패키지되지 않은 Win32 앱에서 공유 콘텐츠를 처리하는 방법을 설명합니다.
| 섹션 | 발견할 수 있는 것들 |
|---|---|
| 기능을 선언하기 전에 | 앱이 처리하는 파일 형식 및 형식만 선언합니다. |
| 패키지된 앱에 대한 공유 대상 구현(UWP 및 패키지 데스크톱) | UWP 및 패키지된 데스크톱 앱에 대한 매니페스트 선언 및 활성화 처리 |
| PWA용 Share Target 구현하기 |
share_target 매니페스트 및 POST 처리 |
| 패키지되지 않은 Win32 앱에서 공유 받기 | 패키지 ID 부여 및 공유 대상으로 등록 |
| 모범 사례 | 신뢰할 수 있는 수신 흐름에 대한 권장 사항 |
| 보고서 수신 진행률 | 대규모 또는 오래 걸리는 공유 작업에 대한 상태 보고 |
| Troubleshooting | 일반적인 공유 대상 문제 해결 |
기능을 선언하기 전에
대부분의 공유 대상 통합 버그는 앱이 실제로 처리할 수 있는 것보다 더 많은 것을 선언하는 데서 비롯됩니다. 앱이 <uap:SupportsAnyFileType />선언하면 처리할 수 없는 파일(예: 사용자가 스프레드시트를 공유할 때 나타나는 사진 편집기)을 포함하여 모든 파일 형식에 대해 공유 시트에 표시됩니다.
항상 앱에서 처리할 수 있는 특정 파일 형식 및 데이터 형식만 선언합니다. 다음은 그 예입니다.
<!-- ✓ Correct: declare only what you support -->
<uap:SupportedFileTypes>
<uap:FileType>.jpg</uap:FileType>
<uap:FileType>.png</uap:FileType>
</uap:SupportedFileTypes>
<!-- ✗ Incorrect: declares everything -->
<!-- <uap:SupportsAnyFileType /> -->
<uap:SupportsAnyFileType />는 범용 파일 이동 도구(클라우드 스토리지, 파일 전송 앱)에만 사용하세요. 앱 범주별 선언은 DataFormat 및 FileType 참조 를 참조하세요.
패키지된 앱에 대한 공유 대상 구현(UWP 및 패키지 데스크톱)
이 섹션은 UWP 앱 및 패키지된 데스크톱 앱(WinUI 3, WPF, WinForms)에 적용됩니다. 둘 다 패키지 ID가 있는 MSIX 패키지로 제공되므로 공유 대상을 동일한 방식으로 선언하고 활성화를 처리하는 방법만 다릅니다(2단계에 표시됨).
1. 매니페스트에서 선언
공유 대상으로 등록하려면 package.appxmanifest을(를) 편집하세요. 앱에서 처리하는 파일 형식 및 데이터 형식 만 선언합니다.
<Extensions>
<uap:Extension Category="windows.shareTarget">
<uap:ShareTarget>
<uap:SupportedFileTypes>
<uap:FileType>.jpg</uap:FileType>
<uap:FileType>.jpeg</uap:FileType>
<uap:FileType>.png</uap:FileType>
<uap:FileType>.gif</uap:FileType>
<uap:FileType>.bmp</uap:FileType>
</uap:SupportedFileTypes>
<uap:DataFormat>Bitmap</uap:DataFormat>
</uap:ShareTarget>
</uap:Extension>
</Extensions>
2. 공유 활성화 처리
앱이 공유 대상으로 활성화되면 OnShareTargetActivated 이벤트를 처리하세요:
메모
OnShareTargetActivated는 UWP 앱(Windows.UI.Xaml.Application)의 활성화 오버라이드입니다. 패키지된 데스크톱 앱(WinUI 3, WPF, WinForms)은 AppInstance.GetActivatedEventArgs를 통해 공유 활성화를 받고 ExtendedActivationKind.ShareTarget를 확인합니다.
패키지된 앱에 대한 활성화 정보 가져오기를 참조하세요.
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
shareOperation.ReportStarted();
try
{
if (shareOperation.Data.Contains(StandardDataFormats.StorageItems))
{
IReadOnlyList<IStorageItem> items = await shareOperation.Data.GetStorageItemsAsync();
// Validate: check count, types, and sizes
if (items.Count == 0)
{
shareOperation.ReportError("No items received.");
return;
}
var file = (IStorageFile)items[0];
// Process the file
await ProcessImageAsync(file);
}
shareOperation.ReportCompleted();
}
catch (Exception ex)
{
shareOperation.ReportError($"Error: {ex.Message}");
}
}
private async Task ProcessImageAsync(IStorageFile file)
{
// Your processing logic here
}
Windows 앱 SDK 사용하여 빌드된 패키지 데스크톱 앱(WinUI 3, WPF, WinForms)의 경우 재정의가 없습니다OnShareTargetActivated. 대신 Main 메서드에서 활성화 상태를 검사하고 ExtendedActivationKind.ShareTarget가 있는지 확인하세요.
using Microsoft.Windows.AppLifecycle;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.DataTransfer;
[STAThread]
static void Main(string[] args)
{
AppActivationArguments activatedArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
if (activatedArgs.Kind == ExtendedActivationKind.ShareTarget)
{
HandleShareAsync(activatedArgs.Data as ShareTargetActivatedEventArgs);
}
else
{
// Normal launch path
}
}
static async void HandleShareAsync(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
shareOperation.ReportStarted();
if (shareOperation.Data.Contains(StandardDataFormats.StorageItems))
{
IReadOnlyList<IStorageItem> items = await shareOperation.Data.GetStorageItemsAsync();
// Process the shared items.
}
shareOperation.ReportCompleted();
}
3. 선언할 데이터 형식 선택
다음 참조를 사용하여 선언할 항목을 결정합니다.
| 포맷 | 사용 시기 | 앱 예제 |
|---|---|---|
StorageItems |
앱에서 파일을 받습니다. | 사진 편집기, 문서 뷰어 |
Bitmap |
앱이 이미지를 받습니다. | 이미지 뷰어, 앱 디자인 |
Text |
앱이 일반 텍스트를 받습니다. | 노트 앱, 텍스트 편집기 |
Html |
앱이 리치 텍스트 콘텐츠를 수신합니다. | 전자 메일 클라이언트, 풍부한 편집기 |
Uri / WebLink |
앱이 링크를 처리합니다. | 브라우저, 링크 관리자 |
Rtf |
앱에서 서식이 지정된 텍스트를 받습니다. | 워드 프로세서 |
자세한 내용은 DataFormat 및 FileType 참조를 참조하세요.
프로그레시브 웹 앱(PWA)용 Share Target 구현
Windows PWA는 웹앱 매니페스트를 통해 공유 대상으로 등록됩니다.
share_target 항목을 추가합니다:
{
"name": "My PWA",
"short_name": "MyPWA",
"share_target": {
"action": "/share",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"title": "title",
"text": "text",
"url": "url",
"files": [
{
"name": "media",
"accept": ["image/*", "video/*"]
}
]
}
}
}
/share 경로에서 POST 요청을 처리하세요:
app.post('/share', async (req, res) => {
const { title, text, url, files } = req.body;
// Validate and process
if (files && files.length > 0) {
const file = files[0];
// Process the file
console.log('Received file:', file.originalname);
}
if (text) {
console.log('Received text:', text);
}
res.redirect('/');
});
PWA에서 처리할 수 있는 파일 형식만 선언합니다. 예를 들어 앱이 모든 파일을 실제로 처리하지 않는 한 수락 형식으로 선언 * 하지 마세요.
패키지되지 않은 Win32 앱에서 공유 받기
공유 대상으로 등록하려면 앱에 패키지 ID가 필요합니다. Win32 앱이 패키지되지 않은 경우 다음 두 가지 방법 중 하나로 패키지 ID를 부여합니다.
- MSIX를 사용하여 다시 패키징(기본 설정): Visual Studio Windows 애플리케이션 패키징 Project 템플릿을 사용하여 신뢰할 수 있는 깨끗한 설치를 수행합니다. MSIX 패키징에 대한 데스크톱 애플리케이션 설정을 참조하세요.
- 외부 위치 (스파스 패키지)가 있는 패키지: ID, 공유 대상 등록 및 시각적 자산을 전달하는 빈 MSIX 패키지를 추가하고 기존 설치 관리자는 앱 이진 파일을 계속 관리합니다. MSIX로 이동할 수 없는 설치 관리자가 있는 경우에만 사용합니다.
이 섹션의 나머지 부분에서는 외부 위치 접근 방식을 안내합니다.
1. 패키지 매니페스트 작성
AppxManifest.xml를 설정하고, ID와 기능을 선언하며, 공유 대상을 등록하는 <uap10:AllowExternalContent>을 만듭니다.
Publisher 및 서명 인증서와 PackageName, ApplicationId, .exe.manifest를 동기화된 상태로 유지하세요.
<Identity Name="PhotoStoreDemo" ProcessorArchitecture="neutral" Publisher="CN=YourPubNameHere" Version="1.0.0.0" />
<Properties>
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
</Capabilities>
<Applications>
<Application Id="PhotoStoreDemo" Executable="PhotoStoreDemo.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<Extensions>
<uap:Extension Category="windows.shareTarget">
<uap:ShareTarget Description="Send to PhotoStoreDemo">
<uap:SupportedFileTypes>
<uap:FileType>.jpg</uap:FileType>
<uap:FileType>.png</uap:FileType>
</uap:SupportedFileTypes>
<uap:DataFormat>StorageItems</uap:DataFormat>
<uap:DataFormat>Bitmap</uap:DataFormat>
</uap:ShareTarget>
</uap:Extension>
</Extensions>
</Application>
</Applications>
실행 파일을 패키지 ID에 연결하는 애플리케이션 매니페스트(YourApp.exe.manifest)를 추가합니다.
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="PhotoStoreDemo.app" />
<msix xmlns="urn:schemas-microsoft-com:msix.v1"
publisher="CN=YourPubNameHere"
packageName="PhotoStoreDemo"
applicationId="PhotoStoreDemo" />
</assembly>
2. 패키지 만들기 및 서명
MakeAppx.exe 스위치와 함께 /nv를 사용하여 매니페스트만 포함된 패키지를 빌드한 다음, SignTool.exe를 사용하여 신뢰할 수 있는 인증서로 서명합니다:
MakeAppx.exe pack /d <folder with AppxManifest.xml> /p <output>\mypackage.msix /nv
SignTool.exe sign /fd SHA256 /a /f <path to cert> /p <cert key> <path to package>
컴퓨터의 신뢰할 수 있는 위치에 서명 인증서를 설치합니다.
3. 처음 실행할 때 패키지 등록
처음 실행할 때 앱이 ID로 다시 시작되도록 외부 위치 패키지를 등록합니다. 외부 위치 및 서명 .msix된 위치에 대한 절대 경로를 제공합니다.
[STAThread]
public static void Main(string[] cmdArgs)
{
if (!ExecutionMode.IsRunningWithIdentity())
{
string externalLocation = Environment.CurrentDirectory;
string externalPkgPath = externalLocation + @"\PhotoStoreDemo.package.msix";
if (registerPackageWithExternalLocation(externalLocation, externalPkgPath))
{
// Registration succeeded - restart so the app runs with identity.
// Join the arguments into a single string; cmdArgs.ToString() would
// return the array type name ("System.String[]"), not the arguments.
string forwardedArgs = cmdArgs is null ? string.Empty : string.Join(" ", cmdArgs);
Process.Start(Application.ResourceAssembly.Location, arguments: forwardedArgs);
}
else
{
// Registration failed - run without identity.
new SingleInstanceManager().Run(cmdArgs);
}
}
}
4. 공유 활성화 처리
ID를 사용하여 앱을 다시 시작한 후 ExtendedActivationKind.ShareTarget에 표시된 대로 처리 합니다.
전체 예제는 PhotoStoreDemo 샘플(외부 위치로 패키지됨) 및 WinUI 공유 대상 샘플을 참조하세요.
원본 쪽 데스크톱 공유의 경우 IDataTransferManagerInterop에 설명된 대로 사용합니다.
최선의 구현 방법
수신 흐름을 빌드할 때 이 검사 목록을 사용합니다.
| 권장 | 피하기 | 중요한 이유 |
|---|---|---|
| 특정 파일 확장자 및 데이터 형식만 선언 |
<uap:SupportsAnyFileType /> 파일 이동 앱이 아닌 앱에 대한 선언 |
Share Sheet에서 관련 없는 대상 표시 방지 |
| 처리하기 전에 형식, 개수, 파일 형식 및 파일 크기의 유효성을 검사합니다. | 들어오는 데이터가 항상 예상과 일치한다고 가정 | 런타임 오류 및 중단된 공유 환경 방지 |
링크 처리기에 대해 Uri 선언하고 이미지 처리기에 대해 Bitmap + StorageItems 선언 |
공통 공유 페이로드에 대한 부분 선언 | 앱이 실제로 지원하는 콘텐츠에 대해 표시되는지 확인합니다. |
장기 실행 수신 흐름에서 ReportStarted, ReportDataRetrieved 및 ReportCompleted 사용 |
진행률 보고 없이 장시간 실행되는 수신 작업 수행 | 공유 작업을 안정적으로 유지하고 시스템에 올바른 상태를 제공합니다. |
보고서 수신 진행률(선택 사항이지만 권장)
큰 페이로드 또는 더 긴 처리의 경우 공유 대상에서 상태를 보고합니다.
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
shareOperation.ReportStarted();
try
{
// Acquire the data your app needs.
var items = await shareOperation.Data.GetStorageItemsAsync();
shareOperation.ReportDataRetrieved();
// Process data.
await ProcessAsync(items);
shareOperation.ReportCompleted();
}
catch (Exception ex)
{
shareOperation.ReportError($"Share failed: {ex.Message}");
}
}
이후 공유를 위해 QuickLink를 반환하려는 경우에 사용합니다 ReportCompleted(QuickLink) .
Troubleshooting
내 앱이 공유 시트에 표시되지 않습니다.
- 매니페스트 선언이 공유되는 콘텐츠와 일치하는지 확인합니다(파일 형식 및 데이터 형식 확인).
- 패키지된 앱의 경우 패키지 ID를 사용하여 앱을 실행하고 있는지 확인합니다.
- 앱 범주에 대한 DataFormat 및 FileType 참조 를 확인합니다.
내 앱이 처리할 수 없는 콘텐츠에 표시됨:
-
SupportedFileTypes및DataFormat목록을 지원하는 항목으로만 좁히세요.
공유 시트는 다음과 같은 오류로 해제됩니다.
- 비동기 작업을 시작하기 전에
ReportStarted()를 호출하고, 완료되면ReportCompleted()를 호출해야 합니다. - 예외를 처리하고 설명 메시지와 함께
ReportError()를 호출합니다.
예상한 파일이 수신되지 않습니다.
- 파일 형식이
FileType또는DataFormat로 선언된 형식과 일치하는지 확인하세요. - 활성화 처리기에 유효성 검사 논리를 추가하여 실제로 도착하는 항목을 검사합니다.
관련 콘텐츠
Windows developer