{"id":21152152,"url":"https://github.com/godrm/coffeechat","last_synced_at":"2025-07-09T10:32:38.843Z","repository":{"id":148238985,"uuid":"562105705","full_name":"godrm/CoffeeChat","owner":"godrm","description":"Let'Swift 2022 Session Demo for Extension","archived":false,"fork":false,"pushed_at":"2022-11-24T02:13:42.000Z","size":446,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T22:01:36.629Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/godrm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-05T10:28:23.000Z","updated_at":"2022-12-01T21:09:38.000Z","dependencies_parsed_at":"2023-05-19T12:30:39.031Z","dependency_job_id":null,"html_url":"https://github.com/godrm/CoffeeChat","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/godrm/CoffeeChat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godrm%2FCoffeeChat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godrm%2FCoffeeChat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godrm%2FCoffeeChat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godrm%2FCoffeeChat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/godrm","download_url":"https://codeload.github.com/godrm/CoffeeChat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godrm%2FCoffeeChat/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264440298,"owners_count":23608690,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-20T10:35:33.379Z","updated_at":"2025-07-09T10:32:38.835Z","avatar_url":"https://github.com/godrm.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CoffeeChat 예제 프로젝트\n\n\u003e 이 프로젝트는 Let'Swift 2022 세션 데모를 위한 예제입니다\n\n### 확장도구 Extension\n\n- 가장 유명한 건 위젯 Widget. 홈화면이 동작시켜주는 특별한(?) 확장도구\n- macOS나 iOS 앱 내에 Extension 타깃을 추가해서 같이 배포. `Containing App`이라고 부름\n- 종류가 무지 많음 [앱 익스텐션 공식 문서](https://developer.apple.com/kr/app-extensions/)\n\t- 동작Action, 공유, 콘텐츠 차단, 메시지 필터, 알림 서비스, 맞춤형 키보드, 스티커팩, Intent(시리)...\n- Containing App에서 App Extension을 포함해서 배포하지만, 각각 다른 앱에서 실행함. \n- Containing App와 App Extension이 리소스를 공유하려면 Group Container 설정 필수\n- Containing App와 App Extension은 서로 다른 프로세스라서 IPC로 통신 가능\n\n### 사파리 확장도구\n\n- Safari Extension 타깃을 추가할 때 Type을 Web Extension 또는 App Extension 두 가지 중에 하나를 선택해야 함\n\n#### I. 사파리 웹 익스텐션\n\n- Safari Web Extension은 사파리 확장도구로 JS코드로 동작하는 브라우저 프로그램 표준. \n파폭이나 크롬 확장은 별도 배포가 가능하지만, macOS와 iOS는 보안상의 이유로 네이티브 앱과 같이 배포해야함\n(예전의 Safari Extension과 동작 방식이 다름)\n\n[사파리 웹 확장 개발문서](https://developer.apple.com/documentation/safariservices/safari_web_extensions)\n\n- 사파리 확장도구와 NSExtensionRequestHandling 상속받은 네이티브 클래스 SafariWebExtensionHandler가 서로 소통할 수 있음\n단, 웹 확장의 background.js에서만 네이티브와 소통이 가능\n\n```js\nbrowser.runtime.sendNativeMessage('kr.letswift.CoffeeChat.SafariChat', {\n        \"body\" : request.body,\n        \"location\" : request.location.href});\n```\n\n- 예제 코드는 다음과 같이 동작함 (👉SafariChat 타깃)\n\t- 사파리에서 확장도구 버튼을 누를 때 popup.js 실행. popup.js에서 활성화된 Tab에 browser.tabs.sendMessage() 보냄\n\t- 탭별로 콘텐츠에 접근가능한 content.js가 실행. 보안상 다른 탭에는 접근 안됨. document에 접근해서 body를 background.js로 보냄\n\t- 확장도구별로 네이티브 코드와 소통할 수 있는 별도 스레드로 동작하는 공용 background.js 실행. 여기서만 SafariWebExtensionHandler로 호출 가능. background.js에서 body는 Group Container에 파일로 저장\n\t- SafariWebExtensionHandler에서 Containing App으로 UDP로 파일 경로를 포함한 이벤트 전달\n\t- Containing App에서는 UDP 서버를 듣고 있다가 메시지 오면 Notification을 띄움\n\n#### II. 사파리 웹 익스텐션\n\n- Safari App Extension은 애플 규격으로 사파리 앱이 실행해주는 익스텐션 \n마찬가지로 macOS와 iOS는 보안상의 이유로 네이티브 앱과 같이 배포해야함\n \n[사파리 앱 확장 개발문서](https://developer.apple.com/documentation/safariservices/safari_app_extensions)\n\n- 예제 코드는 다음과 같이 동작함 (👉SafariAppChat 타깃)\n    - Info.plist 에 모든 설정이 들어감. 이걸 보고 사파리가 실행해줌\n        - SFSafariContentScript : 사파리가 실행할 JS  \n            - 현재는 사파리 웹 페이지와 동작하는 리소스 script.js        \n        - SFSafariToolbarItem : 사파리에 표시될 툴바 정보. Command는 누르면 끝. Popover는 ViewController를 띄움        \n        - SFSafariWebsiteAccess : 접근 허용할 사이트 주소. 현재 letswift.kr 만 \n    - 익스텐션과 소통할 방법은 총 3가지\n        - SFSafariContentScript -\u003e page 관련 메시지 보내기 (현재 로그만 찍음)\n        - SFSafariToolbarItem + Command 방식 -\u003e 누를 때마다 처리 (지금 방식)\n        - SFSafariToolbarItem + Popover + ViewController 방식 -\u003e UI화면에서 연동 \n\n- Web Extension과 다르게 네이티브 UI + 코드를 작성할 수 있음\n- 권한관리가 모두 plist에서 관리되서 앱 개발자가 익숙함. js빼고는 모두 스위프트 코드로 가능!\n- content 접근은 js로 할 수 있는데, 백그라운드 워커 동작은 안되는 듯 (모든 상황을 테스트해보지는 않았음)\n\n---\n\n### Xcode 확장도구 \n\n- Xcode 소스편집기에서 선택된 소스를 전달할 수 있는 맥용 확장도구를 만들 수 있음\n- 플러그인을 만들 수 있던 적이 있었는데, 보안상의 이유로 다 막히고 XcodeKit으로 소스편집기 확장도구만 가능\n- 구조는 2단계로 구성됨\n\t- 1단계. Xcode 메뉴에 아이템 추가 XCSourceEditorExtension 상속\n\t- 2단계. 메뉴를 눌렀을 때 동작할 코드 XCSourceEditorCommand 상속\n\n- 예제에서는 2가지 메뉴가 동작\n\t- SnapshotCommand : 선택된 소스 코드를 문법 하일라이트해서 이미지로 변환. 클립보드에 복사함\n\t- ChatCommand : \n\t\t- Containing App이 떠있으면 UDP로 이벤트 전달\n\t\t- UDP는 MTU 사이즈 제한이 있음. 소스 코드는 Group Containter 폴더에 파일로 저장하고 경로+파일을 전달\n\t\t- Containing App에서는 UDP 서버를 듣고 있다가 메시지 오면 Notification을 띄움\n\n### 기타\n\n- Extension 확장도구는 디버깅하기 어렵다. Safari나 Xcode를 별도로 띄워서 실행은 가능하긴 함\n- 디버깅이 아니라 앱 스토어에 배포하기 전에 사용하려면 아카이브하고, 아카이브 내에 실행 파일을 추출해서 가능함\n- 거쳐가는 단계가 많다보니 어느 단계가 안되는지 판단하려면 os_log를 추천\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodrm%2Fcoffeechat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgodrm%2Fcoffeechat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodrm%2Fcoffeechat/lists"}