SlideShare a Scribd company logo
1 of 57
Download to read offline
이다혜
우당탕탕! Safari Extension에서
Xcode Extension까지.
왕초보의 앱 확장 프로그램 개발 입문하기
GNU CS 4th
dadahae
• 이다혜
• 무소속
• 이제 막 1년차
• 현재 멋쟁이사자처럼 앱스쿨 1기
수강 중
소개
들어가기 전에…
어디에서요?
발표 하시죠
😬
Extension!
아~ 이것보다는 잘 만들겠다
기본적인 구동원리가 이렇구나
👏 성공
목차
앱 확장 프로그램 개발 입문하기
#1 앱 확장 프로그램이 뭔가요
#2 Safari Extension
#3 Xcode Extension
#1 앱 확장 프로그램?
한번씩 써봤을 확장 프로그램(extension)
사파리, 엑스코드 말고도 다른 거
#1 앱 확장 프로그램?
#1 앱 확장 프로그램?
애플의 앱 확장 프로그램
App Extension
- widget
- Custom Keyboard
- Share
- 등등… 많다
#1 앱 확장 프로그램?
https://developer.apple.com/kr/app-extensions/
#1 앱 확장 프로그램?
#1 앱 확장 프로그램?
#1 앱 확장 프로그램?
Containing app
Containing App
Safari App Extension
Xcode Source Editor Extension
Shared Resource
Group Container 설정 필수
#2 Safari Extension
Safari Services
#2 Safari Extension
• 웹 뷰와 웹 서비스를 앱에서 사용할 수 있게 한다.
• iOS나 macOS 앱에서 Safari를 사용하거나, Safari에 익스텐션을 추가할 수 있다.
• SFSafariView
• Safari Extension
Demo
• SafariChat : 사파리 익스텐션 버튼 누르면, Containing App에서는 UDP 서버를 듣고 있다가
메세지가 오면 사용자 Noti 보낸다.
Enable web views and services in your app.
사파리 익스텐션도 다 같은게 아니에요
Safari Web Extension
Safari App Extension
#2 Safari Extension
• 기존 Safari Extension에 존재
• macOS
• Native Code (Swift, Objective-C)
• 기본 macOS 앱과 Safari 간의 코드 공유에 유용
• iOS, macOS에서 web extension 지원
• JavaScript, HTML, CSS
• 다른 브라우저에서 작동하도록 리패키징
이미 다른 브라우저에 돌아가는 익스텐션 프로젝트가 있다면?
HTML, CSS, JS에 익숙하다면?
→ 다시 native로 다시 만들 필요없이 Safari Web Extension으로 리패키징
→ Native 코드로 꼭 작성해야 하나?
Safari Web Extension
#2 Safari Extension
• 앱스토어에 배포 가능
• Native app + extension 동시에 설치
• Javascript API + Chrome, Firefox, Edge 등의 브라우저의 공통 파일 형식 사용
• 향상된 사용자 정보 보호 기능 제공
• JS, HTML, CSS 기반으로 개발하여 다른 브라우저에서 작동하도록 리패키징 가능
Create web extensions that work in Safari and other browsers.
새로운 Safari Web Extension 만들기
#2 Safari Extension
1. Xcode File > New > Target
2. macOS 탭에서 Safari Extension을 찾자.
- Safari Extension 옵션 선택
3. 짜잔! 새로운 폴더가 생성되었습니다.
- 어떤 파일이 있는지 살펴보자구요.
4. 빌드하면 무슨 일이?
macOS 앱에 타겟을 추가하자.
1. Xcode File > New > Target
1. Xcode File > New > Target
2. macOS 탭에서 Safari Extension을 찾자.
2. macOS 탭에서 Safari Extension을 찾자.
3. 짜잔! 새로운 폴더가 생성되었습니다.
3. 짜잔! 새로운 폴더가 생성되었습니다.
• name key 값으로 익스텐션 이름을 지정함
• name key 값은 로컬라이징을 할 수 있는 특수한 문자열이다.
그래서 locales 폴더에 정의되어 있습니다!
익스텐션에 대한 전체적인 구조를 정의한 파일
manifest.json
UI가 따로 없고 익스텐션을 구동하는 로직 정의
background.js
3. 짜잔! 새로운 폴더가 생성되었습니다.
웹페이지에서 수행하는 작업에 대한 코드 정의
3. 짜잔! 새로운 폴더가 생성되었습니다.
sendMessage API를 사용하여
background.js 에서 처리되는 메시지를 전송
content.js
3. 짜잔! 새로운 폴더가 생성되었습니다.
popup
사용자가 사파리 툴바에서 익스텐션 버튼을 클릭할 때 나타나는 팝업
권한 설정하기
#2 Safari Extension
menifest.json
- 네이티브 앱과 통신할 권한(nativeMessaging) 설정
- content.js를 삽입할 도메인을 정의
Permission
background page -> app extension 통신을 위해 사용하는 nativeMessaging 권한
all_urls 권한 키를 사용하여 모든 항목에 대한 접근 요청
Safari web extension과 App이 대화하기
#2 Safari Extension
네이티브 메시징 API(native messaging API)를 사용하여 네이티브 앱과 통신하는 방법
https://developer.apple.com/videos/play/wwdc2020/10665
#2 Safari Extension
https://developer.apple.com/videos/play/wwdc2020/10665
[WWDC20] Meet Safari Web Extensions
popup.js
content.js
background.js
SafariWeb Extension Handler
Containing App
sendMessage(greeting:”pass”)
onMessage(greeting:”pass”)
sendResponse(“passed”)
sendMessage(greeting:”pass”)
browser.runtime.sendNativeMessage
여기서만 SafariWebExtensionHandler로 호출 가능.
(background.js에서 body는 Group Container에 파일로 저장)
SafariWeb Extension Handler
Containing App
Xcode Extension Handler
Containing App으로 UDP로 파일 경로를 포함한 이벤트 전달
UDP 서버를 듣고 있다가 메세지가 오면 Noti
fi
cation을 띄움
새로운 Safari App Extension 만들기
#2 Safari Extension
다 똑같은데…
Type만 설정해주면 된다.
macOS 앱에 타겟을 추가하자.
Info
Build 전 세팅
#2 Safari Extension
Safari > 개발자용 (해당 탭이 안보인다면 사파리 설정에서 보여주게 할 것)
Safari > Preference(환경설정) > 확장프로그램
시스템 설정 > 알림 허용 (Noti
fi
cation을 사용한다면)
#3 Xcode Extension
XcodeKit
#3 Xcode Extension
• Xcode에 명령을 익스텐션으로 추가합니다.
• Xcode Source Editor Extension
Create extensions to add commands to the Xcode source editor.
Demo
• ChatCommand : Xcode Extension으로 Noti 보냄
• SnapshotCommand : 선택된 코드를 Snapshot. 클립보드로 복사.
새로운 Xcode Source Editor Extension 만들기
1. Xcode File > New > Target
2. macOS 탭에서 Xcode Source Editor를 찾자.
3. 짜잔! 새로운 폴더가 또 생성되었습니다.
4. 빌드하면 어떻게 될까요?
macOS 앱에 타겟을 추가하자.
#3 Xcode Extension
SourceEditorExtension
import Foundation
import XcodeKit
class SourceEditorExtension: NSObject, XCSourceEditorExtension {
func extensionDidFinishLaunching() {
// If your extension needs to do any work at launch, implement this optional method.
}
/// Xcode Extension으로 사용할 command들을 배열로 리턴해주기
/// 이때 command들은 Editor 탭에서 확인할 수 있다.
var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] {
/// ChatCommand, ShapshotCommand 등록
let namespace = Bundle(for: type(of: self)).bundleIdentifier!
let snapshotMarker = SnapshotCommand.className()
let chatMarker = ChatCommand.className()
return [[.identifierKey: namespace + chatMarker,
.classNameKey: chatMarker,
.nameKey: NSLocalizedString("Chat", comment: "Send the code to chat")],
[.identifierKey: namespace + snapshotMarker,
.classNameKey: snapshotMarker,
.nameKey: NSLocalizedString("Xshot", comment: "Snap code")]]
}
}
ChatCommand
import Foundation
import XcodeKit
import Network
class ChatCommand: NSObject, XCSourceEditorCommand {
var connection : NWConnection?
override init() {
self.connection = NWConnection.init(host: .init(stringLiteral: "127.0.0.1"), port: .init(integerLiteral: 12022), using: .udp)
connection?.start(queue: DispatchQueue.init(label: "sender.xcodechat"))
connection?.stateUpdateHandler = {newState in
switch newState {
case .ready:
break
default:
break
}
}
}
func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {
let selection = invocation.buffer.selections.firstObject as! XCSourceTextRange
var selectionLines = [String]()
for (index, line) in invocation.buffer.lines.enumerated() {
if selection.start.line <= index && index < selection.end.line {
selectionLines.append(line as? String ?? "")
}
}
let selections = selectionLines.joined(separator: "")
/// Safari Web Extension에서
fi
le 단위로 share resource에 저장하는 것과 같은 원리
let cachePath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.dadahae.letchat")?.path
var fileURL = URL.init(fileURLWithPath: cachePath!)
fileURL.appendPathComponent("code.txt")
try? selections.write(toFile: fileURL.path, atomically: true, encoding: .utf8)
self.connection?.send(content: "{ "app":"Xcode", "code" : "(fileURL.path)" }".data(using: .utf8), completion:
NWConnection.SendCompletion.contentProcessed({ error in }))
completionHandler(nil)
}
}
SnapshotCommand
import Foundation
import XcodeKit
import Splash
import Cocoa
class SnapshotCommand: NSObject, XCSourceEditorCommand {
func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void
{
let selection = invocation.buffer.selections.firstObject as! XCSourceTextRange
var selectionLines = [String]()
for (index, line) in invocation.buffer.lines.enumerated() {
if selection.start.line <= index && index < selection.end.line {
selectionLines.append(line as? String ?? "")
}
}
let selections = selectionLines.joined(separator: "")
let systemTheme = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") ?? "Light"
let options = ImageGenerator.Options(code: selections,
outputURL: URL(fileURLWithPath: ""), padding: 10, font: Font(size: 14))
let image = ImageGenerator.buildImage(options: options, isLight: (systemTheme == "Light"))
let board = NSPasteboard.general
board.clearContents()
board.writeObjects([image])
completionHandler(nil)
}
}
#3 Xcode Extension
Build 전 세팅
Safari Extension & Xcode Extension
어려웠어요
익스텐션이 개발이
• 디버깅이 쉽지 않다.
• 권한 설정
• 빌드 후에도 제대로 작동하지 않아…
• 여러가지 설정 켜주기
• 데모 프로젝트 연습해본다고 여러개 만들었다가 이름 똑같아서 충돌남…
혼났습니다
DRX - Deft
중요한건 꺾이지 않는 마음
저의 서포터이신 김정(고드름)님,감사합니다!
🙌
- App Extension
https://developer.apple.com/kr/app-extensions/
https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/index.html#//apple_ref/doc/uid/TP40014214-CH20-SW1
- Safari Extension
https://developer.apple.com/documentation/safariservices
https://www.youtube.com/watch?v=0svfaOMqfgE
https://developer.apple.com/documentation/safariservices
https://developer.apple.com/documentation/safariservices/safari_web_extensions/creating_a_safari_web_extension
https://developer.apple.com/documentation/safariservices/safari_web_extensions/developing_a_safari_web_extension
https://developer.apple.com/videos/play/wwdc2020/10665
https://developer.apple.com/documentation/safariservices/safari_web_extensions/messaging_between_the_app_and_javascript_in_a_safari_web_extension
https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html#//apple_ref/doc/uid/TP40014214-CH2-SW2
- Xcode Extension
https://developer.apple.com/documentation/xcodekit
- Thanks for JK
https://github.com/godrm/CoffeeChat
Reference
Thanks for JK.

More Related Content

Similar to letswift22_우당탕탕 확장 프로그램(이다혜 light).pdf

F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업
NAVER D2
 
센차 터치2 시작하기 | Devon 2012
센차 터치2 시작하기 | Devon 2012센차 터치2 시작하기 | Devon 2012
센차 터치2 시작하기 | Devon 2012
Daum DNA
 
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
Dae Kim
 

Similar to letswift22_우당탕탕 확장 프로그램(이다혜 light).pdf (20)

Svn 사용하기
Svn 사용하기Svn 사용하기
Svn 사용하기
 
Let'Swift 2023 Swift Macro, 어디다 쓰죠?
Let'Swift 2023 Swift Macro, 어디다 쓰죠?Let'Swift 2023 Swift Macro, 어디다 쓰죠?
Let'Swift 2023 Swift Macro, 어디다 쓰죠?
 
Sencha touch2-sdk-tools-window
Sencha touch2-sdk-tools-windowSencha touch2-sdk-tools-window
Sencha touch2-sdk-tools-window
 
AWS Code 서비스 특집 - 아마존 DevOps와 CodeDeploy, CodePipeline (윤석찬)
AWS Code 서비스 특집 - 아마존 DevOps와 CodeDeploy, CodePipeline (윤석찬)AWS Code 서비스 특집 - 아마존 DevOps와 CodeDeploy, CodePipeline (윤석찬)
AWS Code 서비스 특집 - 아마존 DevOps와 CodeDeploy, CodePipeline (윤석찬)
 
F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업
 
20170623 최신OS와 멀티플랫폼 개발 전략 with RAD Studio
20170623 최신OS와 멀티플랫폼 개발 전략 with RAD Studio20170623 최신OS와 멀티플랫폼 개발 전략 with RAD Studio
20170623 최신OS와 멀티플랫폼 개발 전략 with RAD Studio
 
chatbot-seminar-1806
chatbot-seminar-1806chatbot-seminar-1806
chatbot-seminar-1806
 
[H3 2012] 오픈소스로 개발 실력 쌓기
[H3 2012] 오픈소스로 개발 실력 쌓기[H3 2012] 오픈소스로 개발 실력 쌓기
[H3 2012] 오픈소스로 개발 실력 쌓기
 
Java_01 기초
Java_01 기초Java_01 기초
Java_01 기초
 
Java 기초
Java 기초Java 기초
Java 기초
 
[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현
[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현
[네이버오픈소스세미나] Pinpoint를 이용해서 서버리스 플랫폼 Apache Openwhisk 트레이싱하기 - 오승현
 
Express framework tutorial
Express framework tutorialExpress framework tutorial
Express framework tutorial
 
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
[NDC18] 만들고 붓고 부수고 - 〈야생의 땅: 듀랑고〉 서버 관리 배포 이야기
 
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
 
DevOps - CI/CD 알아보기
DevOps - CI/CD 알아보기DevOps - CI/CD 알아보기
DevOps - CI/CD 알아보기
 
Why OpenStack is Operating System?
Why OpenStack is Operating System?Why OpenStack is Operating System?
Why OpenStack is Operating System?
 
[1B3]모바일 앱 크래시 네이버에서는 어떻게 수집하고 보여줄까요
[1B3]모바일 앱 크래시 네이버에서는 어떻게 수집하고 보여줄까요[1B3]모바일 앱 크래시 네이버에서는 어떻게 수집하고 보여줄까요
[1B3]모바일 앱 크래시 네이버에서는 어떻게 수집하고 보여줄까요
 
센차 터치2 시작하기 | Devon 2012
센차 터치2 시작하기 | Devon 2012센차 터치2 시작하기 | Devon 2012
센차 터치2 시작하기 | Devon 2012
 
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
모바일 게임과 앱을 위한 오픈소스 게임서버 엔진 프로젝트 CloudBread 프로젝트
 
생산성을 높여주는 iOS 개발 방법들.pdf
생산성을 높여주는 iOS 개발 방법들.pdf생산성을 높여주는 iOS 개발 방법들.pdf
생산성을 높여주는 iOS 개발 방법들.pdf
 

More from Lee Dahae

More from Lee Dahae (7)

[GitSpace 1회 세미나] fastlane.pdf
[GitSpace 1회 세미나] fastlane.pdf[GitSpace 1회 세미나] fastlane.pdf
[GitSpace 1회 세미나] fastlane.pdf
 
USG iOS 성과발표회 '가사오케' 발표.pdf
USG iOS 성과발표회 '가사오케' 발표.pdfUSG iOS 성과발표회 '가사오케' 발표.pdf
USG iOS 성과발표회 '가사오케' 발표.pdf
 
[adiOS Korea] 발표 키노트(이다혜).pdf
[adiOS Korea] 발표 키노트(이다혜).pdf[adiOS Korea] 발표 키노트(이다혜).pdf
[adiOS Korea] 발표 키노트(이다혜).pdf
 
경상대 멋쟁이사자처럼 8기 정기세션 (9장 Portfoilo 만들기 - media, static).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (9장 Portfoilo 만들기 - media, static).pptx경상대 멋쟁이사자처럼 8기 정기세션 (9장 Portfoilo 만들기 - media, static).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (9장 Portfoilo 만들기 - media, static).pptx
 
경상대 멋쟁이사자처럼 8기 정기세션 (6장 Blog프로젝트 - Model,admin).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (6장 Blog프로젝트 - Model,admin).pptx경상대 멋쟁이사자처럼 8기 정기세션 (6장 Blog프로젝트 - Model,admin).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (6장 Blog프로젝트 - Model,admin).pptx
 
경상대 멋쟁이사자처럼 8기 정기세션 (4장 기본환경 설정).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (4장 기본환경 설정).pptx경상대 멋쟁이사자처럼 8기 정기세션 (4장 기본환경 설정).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (4장 기본환경 설정).pptx
 
경상대 멋쟁이사자처럼 8기 정기세션 (1장 일기장만들기).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (1장 일기장만들기).pptx경상대 멋쟁이사자처럼 8기 정기세션 (1장 일기장만들기).pptx
경상대 멋쟁이사자처럼 8기 정기세션 (1장 일기장만들기).pptx
 

letswift22_우당탕탕 확장 프로그램(이다혜 light).pdf

  • 1. 이다혜 우당탕탕! Safari Extension에서 Xcode Extension까지. 왕초보의 앱 확장 프로그램 개발 입문하기 GNU CS 4th
  • 2. dadahae • 이다혜 • 무소속 • 이제 막 1년차 • 현재 멋쟁이사자처럼 앱스쿨 1기 수강 중 소개
  • 7. 아~ 이것보다는 잘 만들겠다 기본적인 구동원리가 이렇구나
  • 9. 목차 앱 확장 프로그램 개발 입문하기 #1 앱 확장 프로그램이 뭔가요 #2 Safari Extension #3 Xcode Extension
  • 10. #1 앱 확장 프로그램?
  • 11. 한번씩 써봤을 확장 프로그램(extension) 사파리, 엑스코드 말고도 다른 거 #1 앱 확장 프로그램?
  • 12. #1 앱 확장 프로그램?
  • 13. 애플의 앱 확장 프로그램 App Extension - widget - Custom Keyboard - Share - 등등… 많다 #1 앱 확장 프로그램? https://developer.apple.com/kr/app-extensions/
  • 14. #1 앱 확장 프로그램?
  • 15. #1 앱 확장 프로그램?
  • 16. #1 앱 확장 프로그램?
  • 18. Containing App Safari App Extension Xcode Source Editor Extension Shared Resource Group Container 설정 필수
  • 20. Safari Services #2 Safari Extension • 웹 뷰와 웹 서비스를 앱에서 사용할 수 있게 한다. • iOS나 macOS 앱에서 Safari를 사용하거나, Safari에 익스텐션을 추가할 수 있다. • SFSafariView • Safari Extension Demo • SafariChat : 사파리 익스텐션 버튼 누르면, Containing App에서는 UDP 서버를 듣고 있다가 메세지가 오면 사용자 Noti 보낸다. Enable web views and services in your app.
  • 21. 사파리 익스텐션도 다 같은게 아니에요 Safari Web Extension Safari App Extension #2 Safari Extension • 기존 Safari Extension에 존재 • macOS • Native Code (Swift, Objective-C) • 기본 macOS 앱과 Safari 간의 코드 공유에 유용 • iOS, macOS에서 web extension 지원 • JavaScript, HTML, CSS • 다른 브라우저에서 작동하도록 리패키징
  • 22. 이미 다른 브라우저에 돌아가는 익스텐션 프로젝트가 있다면? HTML, CSS, JS에 익숙하다면? → 다시 native로 다시 만들 필요없이 Safari Web Extension으로 리패키징 → Native 코드로 꼭 작성해야 하나?
  • 23. Safari Web Extension #2 Safari Extension • 앱스토어에 배포 가능 • Native app + extension 동시에 설치 • Javascript API + Chrome, Firefox, Edge 등의 브라우저의 공통 파일 형식 사용 • 향상된 사용자 정보 보호 기능 제공 • JS, HTML, CSS 기반으로 개발하여 다른 브라우저에서 작동하도록 리패키징 가능 Create web extensions that work in Safari and other browsers.
  • 24. 새로운 Safari Web Extension 만들기 #2 Safari Extension 1. Xcode File > New > Target 2. macOS 탭에서 Safari Extension을 찾자. - Safari Extension 옵션 선택 3. 짜잔! 새로운 폴더가 생성되었습니다. - 어떤 파일이 있는지 살펴보자구요. 4. 빌드하면 무슨 일이? macOS 앱에 타겟을 추가하자.
  • 25. 1. Xcode File > New > Target
  • 26. 1. Xcode File > New > Target
  • 27. 2. macOS 탭에서 Safari Extension을 찾자.
  • 28. 2. macOS 탭에서 Safari Extension을 찾자.
  • 29. 3. 짜잔! 새로운 폴더가 생성되었습니다.
  • 30. 3. 짜잔! 새로운 폴더가 생성되었습니다. • name key 값으로 익스텐션 이름을 지정함 • name key 값은 로컬라이징을 할 수 있는 특수한 문자열이다. 그래서 locales 폴더에 정의되어 있습니다! 익스텐션에 대한 전체적인 구조를 정의한 파일 manifest.json
  • 31. UI가 따로 없고 익스텐션을 구동하는 로직 정의 background.js 3. 짜잔! 새로운 폴더가 생성되었습니다. 웹페이지에서 수행하는 작업에 대한 코드 정의
  • 32. 3. 짜잔! 새로운 폴더가 생성되었습니다. sendMessage API를 사용하여 background.js 에서 처리되는 메시지를 전송 content.js
  • 33. 3. 짜잔! 새로운 폴더가 생성되었습니다. popup 사용자가 사파리 툴바에서 익스텐션 버튼을 클릭할 때 나타나는 팝업
  • 34. 권한 설정하기 #2 Safari Extension menifest.json - 네이티브 앱과 통신할 권한(nativeMessaging) 설정 - content.js를 삽입할 도메인을 정의 Permission background page -> app extension 통신을 위해 사용하는 nativeMessaging 권한 all_urls 권한 키를 사용하여 모든 항목에 대한 접근 요청
  • 35. Safari web extension과 App이 대화하기 #2 Safari Extension 네이티브 메시징 API(native messaging API)를 사용하여 네이티브 앱과 통신하는 방법 https://developer.apple.com/videos/play/wwdc2020/10665
  • 37. popup.js content.js background.js SafariWeb Extension Handler Containing App sendMessage(greeting:”pass”) onMessage(greeting:”pass”) sendResponse(“passed”) sendMessage(greeting:”pass”) browser.runtime.sendNativeMessage 여기서만 SafariWebExtensionHandler로 호출 가능. (background.js에서 body는 Group Container에 파일로 저장)
  • 38. SafariWeb Extension Handler Containing App Xcode Extension Handler Containing App으로 UDP로 파일 경로를 포함한 이벤트 전달 UDP 서버를 듣고 있다가 메세지가 오면 Noti fi cation을 띄움
  • 39. 새로운 Safari App Extension 만들기 #2 Safari Extension 다 똑같은데… Type만 설정해주면 된다. macOS 앱에 타겟을 추가하자.
  • 40. Info
  • 41. Build 전 세팅 #2 Safari Extension Safari > 개발자용 (해당 탭이 안보인다면 사파리 설정에서 보여주게 할 것) Safari > Preference(환경설정) > 확장프로그램 시스템 설정 > 알림 허용 (Noti fi cation을 사용한다면)
  • 43. XcodeKit #3 Xcode Extension • Xcode에 명령을 익스텐션으로 추가합니다. • Xcode Source Editor Extension Create extensions to add commands to the Xcode source editor. Demo • ChatCommand : Xcode Extension으로 Noti 보냄 • SnapshotCommand : 선택된 코드를 Snapshot. 클립보드로 복사.
  • 44. 새로운 Xcode Source Editor Extension 만들기 1. Xcode File > New > Target 2. macOS 탭에서 Xcode Source Editor를 찾자. 3. 짜잔! 새로운 폴더가 또 생성되었습니다. 4. 빌드하면 어떻게 될까요? macOS 앱에 타겟을 추가하자. #3 Xcode Extension
  • 45.
  • 46.
  • 47. SourceEditorExtension import Foundation import XcodeKit class SourceEditorExtension: NSObject, XCSourceEditorExtension { func extensionDidFinishLaunching() { // If your extension needs to do any work at launch, implement this optional method. } /// Xcode Extension으로 사용할 command들을 배열로 리턴해주기 /// 이때 command들은 Editor 탭에서 확인할 수 있다. var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] { /// ChatCommand, ShapshotCommand 등록 let namespace = Bundle(for: type(of: self)).bundleIdentifier! let snapshotMarker = SnapshotCommand.className() let chatMarker = ChatCommand.className() return [[.identifierKey: namespace + chatMarker, .classNameKey: chatMarker, .nameKey: NSLocalizedString("Chat", comment: "Send the code to chat")], [.identifierKey: namespace + snapshotMarker, .classNameKey: snapshotMarker, .nameKey: NSLocalizedString("Xshot", comment: "Snap code")]] } }
  • 48. ChatCommand import Foundation import XcodeKit import Network class ChatCommand: NSObject, XCSourceEditorCommand { var connection : NWConnection? override init() { self.connection = NWConnection.init(host: .init(stringLiteral: "127.0.0.1"), port: .init(integerLiteral: 12022), using: .udp) connection?.start(queue: DispatchQueue.init(label: "sender.xcodechat")) connection?.stateUpdateHandler = {newState in switch newState { case .ready: break default: break } } } func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { let selection = invocation.buffer.selections.firstObject as! XCSourceTextRange var selectionLines = [String]() for (index, line) in invocation.buffer.lines.enumerated() { if selection.start.line <= index && index < selection.end.line { selectionLines.append(line as? String ?? "") } } let selections = selectionLines.joined(separator: "") /// Safari Web Extension에서 fi le 단위로 share resource에 저장하는 것과 같은 원리 let cachePath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.dadahae.letchat")?.path var fileURL = URL.init(fileURLWithPath: cachePath!) fileURL.appendPathComponent("code.txt") try? selections.write(toFile: fileURL.path, atomically: true, encoding: .utf8) self.connection?.send(content: "{ "app":"Xcode", "code" : "(fileURL.path)" }".data(using: .utf8), completion: NWConnection.SendCompletion.contentProcessed({ error in })) completionHandler(nil) } }
  • 49. SnapshotCommand import Foundation import XcodeKit import Splash import Cocoa class SnapshotCommand: NSObject, XCSourceEditorCommand { func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { let selection = invocation.buffer.selections.firstObject as! XCSourceTextRange var selectionLines = [String]() for (index, line) in invocation.buffer.lines.enumerated() { if selection.start.line <= index && index < selection.end.line { selectionLines.append(line as? String ?? "") } } let selections = selectionLines.joined(separator: "") let systemTheme = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") ?? "Light" let options = ImageGenerator.Options(code: selections, outputURL: URL(fileURLWithPath: ""), padding: 10, font: Font(size: 14)) let image = ImageGenerator.buildImage(options: options, isLight: (systemTheme == "Light")) let board = NSPasteboard.general board.clearContents() board.writeObjects([image]) completionHandler(nil) } }
  • 51. Safari Extension & Xcode Extension
  • 53. • 디버깅이 쉽지 않다. • 권한 설정 • 빌드 후에도 제대로 작동하지 않아… • 여러가지 설정 켜주기 • 데모 프로젝트 연습해본다고 여러개 만들었다가 이름 똑같아서 충돌남… 혼났습니다
  • 54. DRX - Deft 중요한건 꺾이지 않는 마음
  • 56. - App Extension https://developer.apple.com/kr/app-extensions/ https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/index.html#//apple_ref/doc/uid/TP40014214-CH20-SW1 - Safari Extension https://developer.apple.com/documentation/safariservices https://www.youtube.com/watch?v=0svfaOMqfgE https://developer.apple.com/documentation/safariservices https://developer.apple.com/documentation/safariservices/safari_web_extensions/creating_a_safari_web_extension https://developer.apple.com/documentation/safariservices/safari_web_extensions/developing_a_safari_web_extension https://developer.apple.com/videos/play/wwdc2020/10665 https://developer.apple.com/documentation/safariservices/safari_web_extensions/messaging_between_the_app_and_javascript_in_a_safari_web_extension https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html#//apple_ref/doc/uid/TP40014214-CH2-SW2 - Xcode Extension https://developer.apple.com/documentation/xcodekit - Thanks for JK https://github.com/godrm/CoffeeChat Reference