你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS 10 Day By Day: Xcode Source Editor Extensions

iOS 10 Day By Day: Xcode Source Editor Extensions

編輯:IOS開發基礎

63.jpg

  • 原文:iOS 10 Day By Day: Xcode Source Editor Extensions

  • 譯者:CocoaChina--CoderWQ


在 Xcode 8.0的版本裡面,蘋果引入了一個新的面向 macOS 的 App Extension,叫做 Xcode Source Editor(源代碼編輯器)。通過這個源代碼編輯器,我們也擁有了自己編寫一個Xcode插件的能力 。此外,我們再也不用因為Xcode升級,來尋找各種各樣讓Alcatraz正常運行的辦法了。

簡介

Xcode是蘋果開發平台中一個讓開發者又愛又恨的IDE,在使用過程中,我們發現Xcode的插件的數量一直供不應求。開發者可以添加一些功能做為內置功能的擴展。比如檢查拼寫或者轉換所有的 UIColor 使用新的常量。

在Xcode8以前,Xcode是沒有這個能力的。所以Alcatraz填補了這個空白,看上去仿佛Xcode的插件管理器就是Alcatraz。後來由於安全性跟穩定性的擔憂,利用Xcode8做開發,我們再也不能使用Alcatraz了。幸運的是,蘋果添加了新的源代碼編輯器來擴展Xcode的插件功能。

項目

我們創建一個extension來實現替換ASCII字符為表情的功能。舉個例子:比如"That’s a nice thing to say :)"我們想變成That’s a nice thing to say“。往常,如果我們想實現這個功能,我們可能會懷著希望去Github找。我們往下面看:

Emojificator.gif

像我在Day1中創建iMessage App那樣,蘋果這次推出的各類Extensions 跟Xcode Extensions是差不多的,  但這個官方的Xcdoe插件最大的有點就是可以上架Mac App Store。我們可以利用Extension來擴展整個程序,聽上去有點誇張,其實它更像是一種配置選項。Xcode提供了一個沒有UI的菜單選項來運行一個命令。

接下來我們創建一個新的MacOS的項目,名字是Emojificate。這裡要說明一下,我們可以先忽略對Mac app的相關文件,專注於extension方面的事情。

我們需要創建一個新的target,選擇的Xcode Extension,我們還需要取一個獨一無二的名字,我這裡使用的名字是Emojificator_Extension。

Project_Name.png

Xcode創建了我們需要的一切。

Info.plist

我們改變extension的名字,只需要設置Bundle name的key值為Emojificator。

MenuItem.png

像其他的擴展那樣,我們可以在info.plist中定一些屬性。我們展開NSExtension,在下面,我們可以定義extension的type(Xcode.extension.source-editor),以及插件的類名,key名為XCSourceEditorExtensionPrincipalClass ,大家會發現,在我們的這個項目中,類名是SourceEditorExtension。我們還可以定義擴展中,用戶可以執行的命令。

你的擴展還可以包含大量的命令行,在info.plist中我們可以指定他們的順序。在我們的項目中我們只有一個命令行,它被定義在EmojificatorCommand這個類裡,並且包含了XCSourceEditorCommand的協議。如果想定義的這個類的名稱,那麼我們值需要修改XCSourceEditorCommandClassName的值就好了。

這個類並不限制運行命令行的個數,如果你有多個命令行需要執行,都可以放到同一個類中。如果有相同的方法,你還可以抽取出來公用,通常,我們區分不同的命令是通過標識(即XCSourceEditorCommandIdentifier這個key對應的值)來區分的。

最後,我們在簡單說說,修改命令行的名稱。在我們的項目中,XCSourceEditorCommandClassName所對應的值是Emojificate!,修改對應的key,我們就可以修改命令行的名稱咯。

Extension_Attributes_Plist.png

SourceEditorExtension.swift
這個文件我們必須遵守XCSourceEditorExtension這個協議。當我們設置好我們的plist文件後,我們不需要做任何事,系統就已經幫我們初始化好了。如果你想自定義初始化,你需要在extensionDidFinishLaunching這個方法來自定義初始化。

Xcode在啟動時,擴展就會啟動。在命令執行時,擴展只是執行。這麼做的好處就是,快!

菜單項是動態加載的,可以實現 SourceEditorExtension 的 commandDefinitions: 實現,但是這會覆蓋掉 Info.plist 中的定義。

舉個例子,下面的代碼會返回跟工程現在一樣的配置。

var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: AnyObject]] {
    // If your extension needs to return a collection of command definitions that differs from those in its Info.plist, implement this optional property getter.
    return [[
        .classNameKey : "Emojificator_Extension.EmojificateCommand",
        .identifierKey : "com.shinobicontrols.Emojificator_Extension.EmojificateCommand",
        .nameKey : "Emojificate!"
    ]]
}

EmojificatorCommand.swift

通常,Xcode會創建一個SourceEditorCommand的類,不過在這裡,我重新命名成EmojificateCommand了。為了保證跟系統的一致,我們要保證它遵守XCSourceEditorComman

的協議。

import Foundation
import XcodeKit

class EmojificateCommand: NSObject, XCSourceEditorCommand {
}

舉個例子,我們定義了一組表情跟ASCII之間的映射,並且只是用定義好的這些表情。

let asciiToEmojiMap = [
        ":)" : ":)",
        ";)" : ";)",
        ":(" : ":("]
  *Note: Use actual emojis in second column

為了實現把ASCII字符替換成Emoji表情,我們要用2個方法

extension EmojificateCommand {
    /// Returns whether the string contains an item that can be converted into emoji
    func replaceableItemsExist(in string: String) -> Bool {
        for asciiItem in asciiToEmojiMap.keys {
            if string.contains(asciiItem) {
                return true
            }
        }
        return false
    }

    /// Replaces any ASCII items with their emoji counterparts and returns the newly 'emojified' string
    func replaceASCIIWithEmoji(in string: String) -> String {
        var line = string
        for asciiItem in asciiToEmojiMap.keys {
            line = line.replacingOccurrences(of: asciiItem, with: asciiToEmojiMap[asciiItem]!)
        }
        return line
    }
}

最後,我們在.m文件中,實現`perform(with: completionHandler:)`方法,來在xcode命令行執行的時候來調用它。

func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: (Error?) -> Void) {
    let lines = invocation.buffer.lines
    for (index, line) in lines.enumerated() {
       if let line = line as? String,
           replaceableItemsExist(in: line) {
           lines[index] = replaceASCIIWithEmoji(in: line)
       }
    }
    // Command must perform completion to signify it has completed
    completionHandler(nil)
}

在`perform(with: completionHandler:)`方法中,我們有一個invocation變量,類型是XCSourceEditorCommandInvocation,它是命令調用的文件內容,比如.swift文件,oc頭文件,或者空格等字符。我們要做的就是在buffer中根據當前行,獲取我們要的數據。我們還可以使用`completeBuffer`,它可以是字符串或者數組。如果只是簡單的修改一些字符,蘋果建議使用數組來處理,因為Xcode對數組的處理性能更為好。

最後我們調用completionHandler(nil),告訴Xcode命令執行完畢。
Xcode Extension是在一個單獨的進程中運行,這真是極好的,這意味著緩慢執行的命令行並不會影響到Xcode本身的使用。另一件值得注意的,Xcode對命令運行的時間要求極為嚴格,如果沒有在很短時間內完成,你的擴展將會被"點名批評",同時用戶也可以選擇取消命令。

運行"Emojificate"

這有一點跟我們平常開發不一樣的是,Xcode實在測試版本中來測試我們的命令。這個測試版本的Xcode的圖標顏色是灰色的,這有助於我們區分開發的內容。

88.png

下面是執行的效果圖:

89.gif

更多

蘋果的這項舉措必定會大大擴展開發者的生態圈,也會提高了開發者的效率。這些命令的執行,默認僅允許修改一些文件的buffer和沙盒。如果你需要,你可以請求更高的權限。據我所知,未來Xcode工程師會讓這個工具更加強大,所以如果你有一些不能實現的特定目標,還可以將你的用例提交給蘋果公司。

詳情請見WWDC視頻的介紹。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved