공유 타겟 시작하기
이 가이드는 앱이 다른 애플리케이션에서 공유 콘텐츠를 수신할 수 있도록 Capacitor 공유 대상 플러그인을 통합하는 과정을 안내합니다.
npm을 사용하여 플러그인을 설치합니다.
npm install @capgo/capacitor-share-targetnpx cap syncAndroid 구성
Section titled “Android 구성”<activity> 태그 내부의 AndroidManifest.xml에 인텐트 필터를 추가합니다.
텍스트 콘텐츠 수락
Section titled “텍스트 콘텐츠 수락”<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/*" /></intent-filter>이미지 수락
Section titled “이미지 수락”<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /></intent-filter>
<intent-filter> <action android:name="android.intent.action.SEND_MULTIPLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /></intent-filter>모든 콘텐츠 유형 허용
Section titled “모든 콘텐츠 유형 허용”<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="*/*" /></intent-filter>
<intent-filter> <action android:name="android.intent.action.SEND_MULTIPLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="*/*" /></intent-filter>iOS 구성
Section titled “iOS 구성”iOS의 경우 공유 확장을 생성해야 합니다.
1. Xcode에서 공유 확장을 생성합니다.
Section titled “1. Xcode에서 공유 확장을 생성합니다.”- Xcode에서 프로젝트를 엽니다.
- 파일 > 새로 만들기 > 대상으로 이동합니다.
- 확장 프로그램 공유를 선택하고 다음을 클릭합니다.
- 이름을 지정하고(예: “ShareExtension”) 마침을 클릭합니다.
- 메시지가 표시되면 구성표를 활성화합니다.
2. 앱 그룹 구성
Section titled “2. 앱 그룹 구성”- 기본 앱 타겟에서 서명 및 기능으로 이동합니다.
- + 기능을 클릭하고 앱 그룹을 추가합니다.
- 앱 그룹(예:
group.com.yourcompany.yourapp)을 생성하거나 선택합니다. - 공유 확장 대상에 대해 반복합니다.
3. 공유 확장 코드 업데이트
Section titled “3. 공유 확장 코드 업데이트”공유 확장은 기본 앱이 액세스할 수 있도록 공유 데이터를 앱 그룹 컨테이너에 저장해야 합니다.
자세한 iOS 설정은 Apple의 공유 확장 문서를 참조하세요.
기본 사용법
Section titled “기본 사용법”플러그인 가져오기
Section titled “플러그인 가져오기”import { CapacitorShareTarget } from '@capgo/capacitor-share-target';공유 콘텐츠 듣기
Section titled “공유 콘텐츠 듣기”CapacitorShareTarget.addListener('shareReceived', (event) => { console.log('Received share event'); console.log('Title:', event.title); console.log('Texts:', event.texts);
// Handle shared files if (event.files && event.files.length > 0) { event.files.forEach(file => { console.log(`File: ${file.name}`); console.log(`Type: ${file.mimeType}`); console.log(`URI: ${file.uri}`); }); }});다음은 다양한 유형의 공유 콘텐츠를 처리하는 포괄적인 예입니다.
import { CapacitorShareTarget } from '@capgo/capacitor-share-target';
class ShareTargetService { private listener: any;
initialize() { this.listener = CapacitorShareTarget.addListener('shareReceived', (event) => { this.handleSharedContent(event); });
console.log('Share target listener initialized'); }
handleSharedContent(event: any) { console.log('=== Share Received ===');
// Handle title if (event.title) { console.log('Title:', event.title); this.showNotification('Shared: ' + event.title); }
// Handle text content if (event.texts && event.texts.length > 0) { event.texts.forEach((text: string, index: number) => { console.log(`Text ${index + 1}:`, text); this.processSharedText(text); }); }
// Handle files if (event.files && event.files.length > 0) { console.log(`Received ${event.files.length} file(s)`);
event.files.forEach((file: any) => { console.log('File details:'); console.log(' Name:', file.name); console.log(' Type:', file.mimeType); console.log(' URI:', file.uri);
this.processSharedFile(file); }); } }
processSharedText(text: string) { // Check if it's a URL if (this.isURL(text)) { console.log('Shared URL detected:', text); // Handle URL (e.g., create bookmark) this.saveBookmark(text); } else { console.log('Shared text detected'); // Handle plain text (e.g., create note) this.createNote(text); } }
processSharedFile(file: any) { const fileType = file.mimeType.split('/')[0];
switch (fileType) { case 'image': console.log('Processing shared image'); this.handleImage(file); break;
case 'video': console.log('Processing shared video'); this.handleVideo(file); break;
case 'audio': console.log('Processing shared audio'); this.handleAudio(file); break;
case 'application': console.log('Processing shared document'); this.handleDocument(file); break;
default: console.log('Processing generic file'); this.handleGenericFile(file); } }
handleImage(file: any) { // Process image file console.log('Saving image:', file.name); // Implementation: Save to gallery, upload, etc. }
handleVideo(file: any) { // Process video file console.log('Saving video:', file.name); }
handleAudio(file: any) { // Process audio file console.log('Saving audio:', file.name); }
handleDocument(file: any) { // Process document file console.log('Saving document:', file.name); }
handleGenericFile(file: any) { // Process generic file console.log('Saving file:', file.name); }
isURL(text: string): boolean { try { new URL(text); return true; } catch { return false; } }
saveBookmark(url: string) { console.log('Creating bookmark for:', url); // Implementation }
createNote(text: string) { console.log('Creating note with text:', text.substring(0, 50)); // Implementation }
showNotification(message: string) { console.log('Notification:', message); // Show toast or notification }
cleanup() { if (this.listener) { this.listener.remove(); } }}
// Usageconst shareTarget = new ShareTargetService();shareTarget.initialize();
// Cleanup when app closes// shareTarget.cleanup();import { useEffect } from 'react';import { CapacitorShareTarget } from '@capgo/capacitor-share-target';
function useShareTarget(onShareReceived: (event: any) => void) { useEffect(() => { const listener = CapacitorShareTarget.addListener('shareReceived', onShareReceived);
return () => { listener.remove(); }; }, [onShareReceived]);}
// Usage in componentfunction App() { useShareTarget((event) => { console.log('Share received:', event); // Handle shared content });
return <div>Your App</div>;}Vue 통합
Section titled “Vue 통합”import { onMounted, onUnmounted } from 'vue';import { CapacitorShareTarget } from '@capgo/capacitor-share-target';
export default { setup() { let listener: any;
onMounted(() => { listener = CapacitorShareTarget.addListener('shareReceived', (event) => { console.log('Share received:', event); // Handle shared content }); });
onUnmounted(() => { if (listener) { listener.remove(); } }); }};다양한 콘텐츠 유형 처리
Section titled “다양한 콘텐츠 유형 처리”if (event.texts && event.texts.length > 0) { const text = event.texts[0];
if (text.startsWith('http://') || text.startsWith('https://')) { // Handle URL window.open(text, '_blank'); }}if (event.files) { const images = event.files.filter(f => f.mimeType.startsWith('image/'));
images.forEach(async (image) => { // Read and display image const response = await fetch(image.uri); const blob = await response.blob(); const imageUrl = URL.createObjectURL(blob);
// Display or process image console.log('Image URL:', imageUrl); });}if (event.files && event.files.length > 1) { console.log(`Processing ${event.files.length} files`);
const processPromises = event.files.map(file => processFile(file) );
await Promise.all(processPromises); console.log('All files processed');}- 여러 콘텐츠 유형 처리: 텍스트, URL 및 파일을 받을 준비를 하세요.
- 콘텐츠 유효성 검사: 처리하기 전에 MIME 유형을 확인하세요.
- 피드백 제공: 사용자에게 받은 내용을 표시합니다.
- 오류 처리: 파일 URI가 유효하지 않거나 액세스할 수 없을 수 있습니다.
- 리스너 정리: 필요하지 않은 경우 리스너 제거
- 철저하게 테스트: 다양한 앱과 콘텐츠 유형으로 테스트하세요.
- 권한 요청: 일부 파일 형식에는 추가 권한이 필요할 수 있습니다.
일반적인 문제
Section titled “일반적인 문제”Android에서 공유가 작동하지 않습니다.
Section titled “Android에서 공유가 작동하지 않습니다.”android.intent.action.MAIN이 있는 <activity> 태그 내의 AndroidManifest.xml에 인텐트 필터가 올바르게 구성되어 있는지 확인하세요.
iOS 공유 확장 프로그램이 표시되지 않음
Section titled “iOS 공유 확장 프로그램이 표시되지 않음”- 두 대상 모두에 앱 그룹이 구성되어 있는지 확인하세요.
- 공유 확장이 활성화되었는지 확인하세요.
- 공유 확장의 Info.plist 구성이 올바른지 확인하세요.
파일 액세스 오류
Section titled “파일 액세스 오류”try { const response = await fetch(file.uri); const blob = await response.blob(); // Process blob} catch (error) { console.error('Failed to access file:', error); // Show error to user}