[100 Days Of Swift] Project 19. JavaScript Injection

Zion·2022년 2월 19일
1
post-thumbnail

그냥 제목이 구미가 당겨서 따라해봤다.

Apple Share Extension?

이런 Share Extension에 JavaScript code를 주입한 Extension을 만들어 보겠다는 것이다.

Supporting Suggestions in Your App’s Share Extension
-> apple.Article

NS Extension Item 이란?
-> NSExtensionItem - Apple.docs

Goal

- NSExtensionItem을 사용 
- NSExtensionItem에서 JavaScript Code를 사용할 수 있다.

Tutorial

NSExtensionItem 추가 하는 법

File

New

Target


생성!

override func viewDidLoad() {
        super.viewDidLoad()
        
        if let inputItem = extensionContext?.inputItems.first as? NSExtensionItem {
            if let itemProvider = inputItem.attachments?.first {
                itemProvider.loadItem(forTypeIdentifier: kUTTypePropertyList as String) { [weak self] (dict, error) in
                    // do stuff!
                }
            }
        }
    }

Info.plist

NSExtensionAttributes

⌊ Add NSExtensionJavaScriptPreprocessingFile : “Action"

NSExtensionActivationRule (→ Dictionary)

⌊ Add NSExtensionActivationSupportsWebPageWithMaxCount : “1"

var Action = function() {};
    
Action.prototype = {

run: function(parameters) {

},
    
finalize: function(parameters) {
    
}

};

var ExtensionPreprocessingJS = new Action


잘 생성됐는지 확인!

run: function(parameters) {
    parameters.completionFunction({"URL": document.URL, "title": document.title });
},


Run! 클릭

Apple site 접속 → 내보내기(?) 버튼 터치

Extension 클릭


Console 창에 URL과 title이 잘 찍힌다.

Editing multiline text with UITextView

NavigationViewController 의 Root View Controller 를 ActionViewController로 해주고,

아래와 같이 구성한다.

@IBOutlet weak var script: UITextView!
    
    var pageTitle = ""
    var pageURL = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let inputItem = extensionContext?.inputItems.first as? NSExtensionItem {
            if let itemProvider = inputItem.attachments?.first {
                itemProvider.loadItem(forTypeIdentifier: kUTTypePropertyList as String) { [weak self] (dict, error) in
                    guard let itemDictionary = dict as? NSDictionary else { return }
                    guard let javaScriptValues = itemDictionary[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary else { return }
                    
                    self?.pageTitle = javaScriptValues["title"] as? String ?? ""
                    self?.pageURL = javaScriptValues["URL"] as? String ?? ""
                    
                    DispatchQueue.main.async {
                        //page title
						self?.title = self?.pageTitle
                    }
                }
            }
        }
    }


self?.title = self?.pageTitle 코드처럼 title 설정이 잘 됐다.

@IBAction func done() {
        // Return any edited content to the host app.
        // This template doesn't do anything, so we just echo the passed in items.
        let item = NSExtensionItem()
        let argument: NSDictionary = ["customJavaScript": script.text]
        let webDictionary: NSDictionary = [NSExtensionJavaScriptFinalizeArgumentKey: argument]
        let customJavaScript = NSItemProvider(item: webDictionary, typeIdentifier: kUTTypePropertyList as String)
        item.attachments = [customJavaScript]

        extensionContext?.completeRequest(returningItems: [item])
    }
finalize: function(parameters) {
    var customJavaScript = parameters["customJavaScript"];
    eval(customJavaScript);
}

That's all the code required to send data back to Safari, at which point it will appear inside the finalize()
function in Action.js. From there we can do what we like with it, but in this project the JavaScript we need to write is remarkably simple: we pull the "customJavaScript" value out of the parameters
array, then pass it to the JavaScript eval()
function, which executes any code it finds.

Tada👍

참고

https://www.hackingwithswift.com/100/67

profile
어제보다만 나아지는

0개의 댓글