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

Скрываем и показываем иконку приложения в 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 будет представлять скорее академический интерес. С другой стороны, доступного функционала хватит, чтобы изучить основы языка и писать несложные консольные утилиты, не приобретая дорогостоящие устройства, что может оказаться для многих плюсом.

Читать далее →

Принудительное обновление provisioning profile в Xcode 8.3

Xcode Code signing

После обновления в Xсode 8.3 исчезло окно управления provisioning profile проекта. Им было удобно пользоваться для принудительного удаления и скачивания профайлов. Например, когда добавляешь на Developer Portal новые устройства для ad-hoc установки, профайл в Xcode обновляется далеко не сразу и не всегда. Чтобы решить эту проблему, можно было зайти в настройки аккаунта, открыть окно управления профайлами и сертификатами, нажать правой кнопкой мыши на профайле, выбрать «Move to trash», после чего заново скачивался новый.

Сейчас такой возможности нет из-за того, что в Xcode 8 ввели Automatic provisioning, и видимо в Apple сочли, что такая возможность больше не требуется. Проблема же с тем, что профайл не всегда обновляется после внесения изменений на Developer Portal осталась.

Существует очень простое решение: нужно зайти в директорию /Users/michail/Library/MobileDevice/Provisioning\ Profiles (это Library, которая в домашней папке, нужно включить отображение скрытых файлов чтобы её увидеть) и удалить нужные профайлы, или всё содержимое, Xcode потом автоматически загрузит свежие профайлы.

Статический анализ кода при помощи 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

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

Управляем сторонними библиотеками с CocoaPods

Разработка под iOS Разработка под macOS CocoaPods Менеджер пакетов Xcode

CocoaPods — менеджер пакетов, сделанный по образу и подобию RubyGems, позволяющий легко скачивать и подключать сторонние библиотеки к Swift и Objective-C проектам.

Установка CocoaPods

Менеджер пакетов написан на Ruby и распространяется через RubyGems. В общем случае установка сводится к единственной команде в терминале:

sudo gem install cocoapods --pre

Процесс может занять некоторое (продолжительное) время, не выводя ничего на экран, стоит быть к этому готовым и не прерывать установку до завершения (должна появиться надпись вроде «xx gems installed»).

Далее установим мастер-репозиторий CocoaPods со спецификациями всех доступных проектов. Делается это командой в терминале:

pod setup --verbose

Отмечу, что этот шаг тоже занимает достаточно большой промежуток времени, поэтому я указал ключ —verbose, чтобы было видно, что процесс не завис и происходит клонирование репозитория. В зависимости от скорости интернет-соединения, установка мастер-репозитория может занимать от нескольких минут до часа.

Установка и использование библиотек

Чтобы сразу продемонстрировать все возможности создадим новый Swift-проект и установим для него Objective-C компонент под названием BEMCheckBox.

Откроем Xcode и создадим самый простой Single View, Swift-проект, я назову его «CocoaPodsExample». Сохраните его в любое место, закройте Xcode, откройте терминал, перейдите в директорию с проектом и напишите:

pod init

В корне директории должен появиться новый файл: Podfile. Это обычный текстовый файл с конфигурационным кодом на Ruby, в котором мы должны указать требуемые библиотеки. Обычно все солидные opensource-проекты указывают в Readme, что именно нужно прописать в Podfile для установки, и BEMCheckBox здесь не исключение. Откройте его любым текстовым редактором и приведите к следующему виду:

platform :ios, "9.0"

target 'CocoaPodsTest'do
  use_frameworks!

  pod 'BEMCheckBox'
end

Синтаксис должен быть интуитивно понятен: указываем целевую версию платформы, директива use_frameworks! указывает CocoaPods использовать фреймворки вместо статических библиотек (подробности в блоге проекта), а после pod пишем название библиотеки.

Иногда требуется установить не оригинальную библиотеку, а наиболее акутальный форк от другого автора (например, исправление критичного бага, который ещё не успели смерджить) в таком случае можно использовать следующий синтаксис:

pod 'SWRevealViewController', :git => 'git@github.com:safarijv/SWRevealViewController.git', :branch => 'safarijv-additions'

В данном случае мы указываем репозиторий и ветку из которой нужно взять под. Если не указать ветку, то по-умолчанию будет браться master. Аналогично нужно поступать, если вам требуется внести свои изменения в библиотеку: создать форк, закоммитить изменения и сослаться на свой репозиторий в Podfile. Не стоит делать изменения в уже установленных подах, т.к. потом будет очень сложно разобраться (особенно другим разработчикам), почему поведение библиотеки отличается от описанного в оригинальной документации.

Далее запускаем установку командой:

pod install

После окончания установки, в директории с проектом должен появиться файл *.xcworkspace, который объединяет созданный нами проект и проект Pods со всеми необходимыми библиотеками и конфигурационными файлами. Теперь для работы с проектом нужно открывать именно воркспейс, а не сам проект (в противном случае ему не будут видны сторонние библиотеки).

Проверить, что библиотека подключилась легко: перейдите на Storyboard, поместите на ViewController UIView из Object Library и в Identity Inspector поставьте ему класс BEMCheckBox (если не получается, то можно попробовать собрать проект Cmd + B). Запустите проект, и у вас должен появиться работающий чекбокс. Обратите внимание, что мы подключили Objective-C библиотеку к Swift проекту, если вы делали это раньше вручную, то помните, что для этой цели нужно было создавать специальный заголовочный файл Objective-C Bridging Header, но последние версии CocoaPods генерируют его автоматически, поэтому в этом больше нет необходимости.

CocoaPods и системы контроля версий

Обычно хорошим тоном в современной разработке является не добавлять сторонние библиотеки под контроль версий. Однако авторы проекта наоборот, рекомендуют хранить директорию Pods/ вместе с проектом. Преимуществом такого подхода является переносимость проекта и отсутствие зависимости от внешних инфраструктур (например Github, где хранится большинство исходных кодов библиотек). С другой стороны, в крупном проекте со множеством библиотек это может существенно увеличить размер репозитория, а в случае командной разработки добавит головной боли при слиянии веток. Поэтому в небольших проектах, где вы являетесь единственным разработчиком, можно смело оставить директорию Pods/ под контролем версий, а в крупных проектах и при командной разработке, лучше добавить ее в .gitignore.

Исправляем неработающий под Linux тачпад на Asus X550LN

Linux Ubuntu Asus X550LN Тачпад

Примечание от 28.05.2017: Начиная с версии Ubuntu 16.04 проблему с тачпадом наконец-то починили, но тем не менее этот пост всё ещё остаётся актуальным для многих дистрибутивов.

Уже почти год моим основным компьютером является ноутбук Asus X550LN. За это время я неоднократно менял на нем операционные системы, даже пытался жить на Windows, но все время возвращался к излюбленным мной Debian-based дистрибутивам Linux. К сожалению, в 2015 году проблемы с поддержкой аппаратного обеспечения под альтернативными ОС никак не заканчиваются. Так, практически на всех испробованных мной дистрибутивах, не работает тачпад. Проблема проявляется следующим образом: при касании тачпада, в зависимости от дистрибутива, либо не происходит ничего, либо курсор двигается, но невозможно совершить клик, либо же система намертво зависает.

Багтрекер Red Hat рапортует об успешном решении проблемы, в то время как под Ubuntu (и Debian) до сих пор нет полноценного решения. Существует лишь обходной путь с включением тачпада в режиме эмуляции ps/2 мыши (что означает отсутствие мультитача и других продвинутых функций). Его мы и рассмотрим.

При установке системы подключаем и используем внешнюю USB-мышь, тачпад, во избежание проблем, не трогаем.

Для включения режима эмуляции, необходимо добавить параметр загрузки ядра, для чего нужно отредактировать файл /etc/default/grub.

sudo nano /etc/default/grub

Далее находим параметр GRUB_CMDLINE_LINUX_DEFAULT и после quiet splash через пробел добавляем psmouse.proto=bare, сохраняем файл и выходим из редактора.

После выполняем:

sudo update-grub

Теперь после перезагрузки тачпад должен работать нормально и не конфликтовать с внешней мышкой.

Восстанавливаем файлы, удаленные в прошлых коммитах в Git

Git Bash

Сегодня передо мной встала довольно простая, но интересная задача: восстановить несколько файлов в репозитории Git, которые были удалены некоторое время назад в разных коммитах. Задача простая, потому что решение легко найти в соотвествующих ответах на Stack Overflow. Мне лишь осталось слегка адаптировать приведенные примеры команд для своих нужд.

Я не помнил точные названия файлов и уж тем более не знал хэши коммитов, в которых производилось удаление. Поэтому воспользовался сниппетом от пользователя Robert Munteanu, чтобы вывести историю удаленных файлов:

git log --diff-filter=D --summary

Отыскав необходимые файлы и коммиты, можно было бы воспользоваться простым git checkout для восстановления, но список был весьма велик, так что пришлось набросать небольшой скрипт на Bash.

#!/bin/bash

set -o nounset 
set -o errexit

declare -a files=(
    "source/posts/2012-11-11-twitter/Untitled.png"
    "source/posts/2013-06-08-wb/unnamed.png"
    "source/posts/2012-10-13-lift/IMG_0020.png"
);

counter=0
while [ $counter -lt ${#files[@]} ]; do
    file=${files[$counter]}
    commit=$(git rev-list -n 1 HEAD -- "$file") 
    echo Restoring file: $file from commit: $commit
    git checkout $commit^ "$file" 
    let counter+=1
done

В скрипте я объявляю массив с нужными мне файлами (в примере я сократил список). Далее в цикле проходимся по этому списку, при помощи команды git rev-list -n 1 HEAD -- "$file" находим коммит, в котором последний раз использовался этот файл и при помощи git checkout $commit^ "$file" восстанавливаем его из предыдущего коммита (для этого используется символ ^).

Модули Metasploit

Linux Metasploit Безопасность Журнал Хакер Ruby

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

Счет встроенных модулей в Metasploit перешел на тысячи, но, рано или поздно, любой, кто плотно работает с фреймворком, сталкивается с необходимостью расширить его функционал собственными эксплойтами и вспомогательными модулями. Сегодня мы рассмотрим все необходимые аспекты создания модуля с нуля, а также особенности языка Ruby, которые нужно учитывать при написании.

Читать далее →
1 of 2 Туда →