Михаил Овчинников

Скрываем и показываем иконку приложения в Dock на macOS

Разработка под macOS Swift

Думаю всем очевиден факт, что когда приложение в macOS запущено, оно отображает иконку в доке. Иногда нам это не требуется, к примеру, если подразумевается, что приложение будет работать в фоне, и нет нужды лишний раз напоминать пользователю о его существовании.

В общем случае для этого даже не требуется писать код: достаточно выставить соотвествующий флаг в Info.plist.

 <key>LSUIElement</key>
 <true/>

По-человечески этот ключ называется “Application is agent (UIElement)” и собственно он переведет приложение в режим агента, в котором иконка в доке показываться не будет.

Если же поведение твоего приложения ещё более специфично и есть желание управлять отображением иконки в доке в процессе работы, то можно воспользоваться методом setActivationPolicy класса NSApplication.

Чтобы скрыть иконку (по сути этот метод аналогичен выставлению флага в Info.plist):

 NSApp.setActivationPolicy(.accessory)

Вернуть назад приложение в нормальный режим:

 NSApp.setActivationPolicy(.regular)

Показываем индикатор загрузки файла в Finder

Разработка под macOS Swift

Ты наверное замечал, что при загрузке файлов, например в Chrome, в Finder рядом с файлом показывается некий круговой индикатор загрузки.

Отображение индикактора загрузки файла в Finder

Для этого используется специальный атрибут файла com.apple.progress.fractionCompleted, а также есть небольшая (но неочевидная) хитрость: нужно выставить дату создания файла равной 1984-01-24 08:00:00 +0000 а соотвественно, чтобы скрыть индикатор вернуть файлу актуальную дату и убрать атрибут.

Метод на Swift будет выглядеть следующим образом:

func setProgress(value: Double, forFile path: String) throws {
    var fileAttributes = try FileManager.default.attributesOfItem(atPath: path)
    let extendedAttributesKey = FileAttributeKey(rawValue: "NSFileExtendedAttributes")
    var extendedAttributes = fileAttributes[extendedAttributesKey] as? Dictionary ?? [:]
    let progressData = "\(value)".data(using: .ascii)
    extendedAttributes["com.apple.progress.fractionCompleted"] = progressData
    fileAttributes[extendedAttributesKey] = extendedAttributes

    let dateString = "1984-01-24 08:00:00 +0000"
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss Z"
    let date = dateFormatter.date(from: dateString)
    fileAttributes[FileAttributeKey.creationDate] = date

    try FileManager.default.setAttributes(fileAttributes, ofItemAtPath: path)
}

Пример использования:

try! setProgress(value: 0.6, forFile: "/Users/michael/1.txt")

Скачать пример

Программное добавление папки в «Избранное» в Finder

Разработка под macOS Swift Objective-C

Возникла специфическая задача: добавить программно папку в раздел «Избранное» на боковой панели Finder в macOS. Эта и другая подобная информация хранится в *.sfl файлах, в ~/Library/Application Support/com.apple.sharedfilelist/. Работать с ними напрямую не получится, для этого существует системная утилита sfltool.

Через терминал выполняем следующую команду:

/usr/bin/sfltool add-item com.apple.LSSharedFileList.FavoriteItems file:///Users/$USER/Desktop/

Если нужно произвести такую операцию непосредственно из кода программы, то придется работать с API LSSharedFileList, которое объявлено Apple устаревшим, при этом альтернативных способов сделать это компания не предложила. Применяя этот метод, следует также помнить, что он не будет работать в sandbox-режиме.

На Objective-C:

- (void)appendFavoriteItemWithURL:(NSString *)itemPath {
    NSURL *url = [NSURL fileURLWithPath:itemPath];
    LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL);
    if (list) {
        LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(list,
                                                                    kLSSharedFileListItemLast,
                                                                    NULL,
                                                                    NULL,
                                                                    (__bridge CFURLRef)url,
                                                                    NULL,
                                                                    NULL);
        if (item) {
            CFRelease(item);
        }

        CFRelease(list);
    }
}

Пример использования:

NSString * itemPath = [@"~/Documents/src" stringByExpandingTildeInPath];
[self appendFavoriteItemWithURL:itemPath];

На Swift:

func appendFavoriteItemWithURL(itemPath: String) {
    let url = NSURL(fileURLWithPath: itemPath) as CFURL
    let list = LSSharedFileListCreate(nil,
                                    kLSSharedFileListFavoriteItems.takeRetainedValue(),
                                    nil).takeRetainedValue()
    let startPosition: LSSharedFileListItem = kLSSharedFileListItemBeforeFirst.takeRetainedValue()

    LSSharedFileListInsertItemURL(list,
                                startPosition,
                                nil,
                                nil,
                                url,
                                nil,
                                nil)
}

Пример использования:

let itemPath = NSString(string: "~/Documents/src").expandingTildeInPath
appendFavoriteItemWithURL(itemPath: itemPath)

Источники

Установка и использование языка Swift на Ubuntu 16.04

Swift Linux

Некоторое время язык Swift был доступен только для операционной системы OS X, в составе среды разработки Xcode, но недавно на официальном сайте стали доступны сборки и для последних версий Ubuntu. Практической пользы от такого шага не очень много: большинство библиотек так и не были портированы, и разрабатывать для iOS на альтернативных платформах всё еще невозможно. Хотя существует призрачная возможность писать серверный код на том же языке, что и код приложения, но пока инструментарий развит слабо, использование языка от Apple на Ubuntu будет представлять скорее академический интерес. С другой стороны, доступного функционала хватит, чтобы изучить основы языка и писать несложные консольные утилиты, не приобретая дорогостоящие устройства, что может оказаться для многих плюсом.

Установка

Для удобства все действия будем производить в терминале. В стандартной версии Ubuntu его можно открыть сочетанием клавиш ctrl + alt + t.

Cкачаем последнюю стабильную версию Swift с официального сайта:

wget https://swift.org/builds/swift-3.1.1-release/ubuntu1604/swift-3.1.1-RELEASE/swift-3.1.1-RELEASE-ubuntu16.04.tar.gz

Распакуем скачанный архив:

tar xvf swift-3.1.1-RELEASE-ubuntu16.04.tar.gz

Поместим содержимое архива в директорию /opt:

mv swift-3.1.1-RELEASE-ubuntu16.04 /opt/swift

Добавим директорию с исполняемыми файлами в переменную окружения PATH:

echo 'export PATH=/opt/swift/usr/bin:$PATH' >>~/.profile

Выполним команду source, чтобы обновить переменную PATH для текущей сессии:

source ~/.profile

Для работы Swift потребуется clang, установим эту зависимость:

sudo apt-get update
sudo apt-get install clang

На этом установка закончена, теперь можно проверить текщую версию языка командой:

swift --version

В ответ команда должна вернуть текущую версию языка и платформу.

REPL

Запустить интерактивную консоль Swift (REPL — Read Eval Print Loop) можно одноименной командой: swift. В ней можно начать изучение синтаксиса языка, подробнее о её возможностях можно прочитать на сайте Apple. Выйти из REPL можно командой :exit.

Hello world

Напишем и скомпилируем простейший пример, который будет выводить надпись «Hello, Swift». Создайте файл hello.swift, и введите следующий код:

print("Hello, Swift")

Сохраним файл и скомпилируем его командой:

swiftc hello.swift

Теперь выполним его:

./hello

В ответ ожидаемо получим строку «Hello, Swift».

Swift build

Создайте директорию с названием проекта, например Hello. Перейдите в неё и выполните:

swift package init --type executable

Эта команда сгенерирует базовую структуру проекта. Код, который должен выполняться находится в Sources/main.swift, по-умолчанию там написано print("Hello, world!").

Соберем проект командой:

swift build

Результат компиляции будет находиться по следующему пути: .build/debug/Hello (относительно корня проекта). Запустив его, получим тот же результат, что и в предыдущем примере.

Статический анализ кода при помощи SwiftLint

SwiftLint Swift Статический анализатор Xcode

SwiftLint — это статический анализатор Swift-кода, разработанный компанией Realm, который проверяет его на соответствие стилю и соглашениям принятым в сообществе разработчиков. Главным образом он базируется на Swift style guide от Github. Почему это важно? Наличие соглашений и стандартов всегда лучше их отсутствия: код написанный в едином стиле, проще читать при командной разработке, а также косвенно анализаторы кода способны улучшить и стабильность приложения, так как распознают заведомо плохие практики. Начинающим изучать Swift разбор ошибок и предупреждений анализатора поможет разобраться в особенностях языка, а также избежать использования устаревших конструкций, которые могли быть скопированы с сайтов вроде Stack Overflow.

Установка

SwiftLint является консольным приложением и устанавливается через Homebrew, поэтому достаточно ввести команду:

brew install swiftlint

Инструмент можно использовать отдельно, запуская команду swiftlint в консоли, что не очень удобно, поэтому существует довольно простой способ интегрировать его с Xcode.

Интеграция с Xcode

Откройте проект, который вы разрабатываете, зайдите в его настройки, на вкладку Build Phases и добавьте новую фазу сборки с запуском скрипта.

Добавление новой фазы сборки в Xcode

В появившемся поле для ввода нужно добавить следующий код:

if which swiftlint >/dev/null; then
    swiftlint autocorrect
    swiftlint
else
    echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi

Команда swiftlint autocorrect автоматически исправляет простые недочеты вроде пустых строк с пробелами и т.п. Я всегда запускаю ее перед проверкой, чтобы не отвлекаться на тривиальные вещи. Данный скрипт будет выполняться при каждой сборке проекта, а все ошибки и предупреждения будут выводиться наряду со стандартными предупреждениями Xcode.

Настройка правил

Если какие-то из правил вам не подходят (например ограничение длины строки в 100 символов, или размер метода), их легко можно отключить, для этого в корне проекта создается файл под названием: .swiftlint.yml. Например, чтобы отключить предупреждения о превышении допустимой длины строки, в него нужно добавить следующие строки:

disabled_rules:
  - line_length

Названия правил, которые потребуется добавить в файл можно найти в скобках у соответствующего предупреждения. Это не единственные настройки, которые можно задать в конфигурационном файле, более подробно с ними можно ознакомиться в документации на странице проекта.

1 of 1