0
Rating
13 March 2015

Особенности работы с файлами в приложениях на разных мобильных платформах

Edusty corporate blogDevelopment for iOSDevelopment for AndroidDevelopment for Windows PhoneDevelopment for Windows
При разработке кросс-платформенного мобильного приложения, имеющего в своём функционале работу с файлами, встаёт вопрос об организации процессов работы с файлами на каждой платформе. С данным вопросом мы столкнулись при разработке новой версии Edusty, позволяющей делиться файлами со своими одногруппниками. В этой статье мы расскажем как происходит импорт и экспорт файлов в приложениях, работающих на операционных системах iOS, Android, Windows Phone.




iOS


В операционной системе iOS понятие файловая система скрыта для пользователя и взаимодействие с файлами осуществляется средствами самого приложения и только с файлами, расположенными в директории приложения. Импортировать файл в директорию приложения можно несколькими путями – с помощью iTunes File Sharing или регистрацией File Types для приложения.

При использовании iTunes File Sharing приложение будет отображено в iTunes в разделе «Общие файлы», где можно добавить файлы в приложение с компьютера. Файлы, добавленные таким способом, попадают в директорию /Documents приложения.



Приложение должно само контролировать эту директорию, на предмет появления новых файлов. Так же нужно иметь ввиду, что iTunes File Sharing фактически, открывает прямой доступ пользователю к документам, а это означает что файлы в данной директории в любой момент могут быть переименованы, удалены и т. д.

Для использования iTunes File Sharing необходимо добавить флаг UIFileSharingEnabled (Application supports iTunes file sharing) в info.plist файл приложения.

<key>UIFileSharingEnabled</key>
<true/>


При регистрации File Types, приложение появится в списке выбора для открытия файла, при нажатии на стандартное диалоговое меню “открыть с помощью”.



При открытии файла таким способом, его копия помещается в директорию /Documents/Inbox, а в приложении вызывается метод application:openURL:sourceApplication:annotation: протокола UIApplicationDelegate, в котором передаётся url открываемого файла.

Файлы в директории /Documents/Inbox можно читать и удалять, но нельзя изменять. Для изменения файл необходимо перенести в другую директорию, например в /Documents.

Для возможности импорта файлов данным способом необходимо добавить ключ CFBundleDocumentTypes (Document types) в info.plist файл приложения. Его значением является массив, каждый элемент которого словарь, используемый для описания каждого типа документа, поддерживаемого приложением. Полное описание возможных ключений и их значений можно найти в документации: developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html

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

<key>CFBundleDocumentTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeName</key>
			<string>All files</string>
			<key>CFBundleTypeRole</key>
			<string>Viewer</string>
			<key>LSHandlerRank</key>
			<string>Alternate</string>
			<key>LSItemContentTypes</key>
			<array>
				<string>public.data</string>
			</array>
		</dict>
	</array>


Для экспорта файлов из приложения используется тоже самое диалоговое меню “открыть с помощью”, которое инициализирует UIDocumentInteractionController. Есть возможность открыть сразу список приложений для открытия файла, открыть список приложений для открытия файла вместе с стандартными службами, такими как печать файла, пересылка по почте и т.д. а так же есть возможность открыть файл встроенным предпросмоторщиком, откуда так же доступна кнопка для открытия файла другим приложением.



Android


В Android приложения могут получить возможность доступа к файлам, кроме тех, что находятся в приватных директориях приложений.
Для выполнения таких операций как выбор файла, отправка email или открытие ссылки в браузере используются Intents (Намерения).
Чтобы выбрать файл из файловой системы, необходимо использовать действие ACTION_GET_CONTENT.
С помощью метода setType() можно указать какие типы файлов будут доступны для выбора. Например, если указать
setType(“audio/mp3”), то в приложении для просмотра файлов мы будем видеть только файлы с расширением .mp3, или указать “*/*”, чтобы отображались все файлы. После чего вызываем метод startActivityForResult(), где в качестве параметра передаем Intent.сreateChooser(), который создаёт диалог выбора приложения.
Так же в файле манифеста необходимо дописать необходимые разрешения:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />




После того, как мы выбрали файл в файловом менеджере мы попадаем в метод onActivityResult(int requestCode, int resultCode, Intent data), где в data будет Uri нашего файла.

Для открытия файлов из сервиса используется действие ACTION_VIEW. Выбор приложения для открытия файла происходит при помощи класса FileOpen (найденный на просторах StackOverFlow и немного переделанный), в котором проверяем какой тип файла мы пытаемся открыть, согласно его потенциально возможному расширению.

FileOpen.class
public class FileOpen {

    public static void openFile(Context context, File url) throws IOException {
        File file = url;
        Uri uri = Uri.fromFile(file);

        Intent intent = new Intent(Intent.ACTION_VIEW);

        if (url.toString().contains(".doc") || url.toString().contains(".docx") || url.toString().contains(".odt")) {
            // Word document
            intent.setDataAndType(uri, "application/msword");
        } else if (url.toString().contains(".pdf")) {
            // PDF file
            intent.setDataAndType(uri, "application/pdf");
        } else if (url.toString().contains(".ppt") || url.toString().contains(".pptx")) {
            // Powerpoint file
            intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
        } else if (url.toString().contains(".xls") || url.toString().contains(".xlsx")) {
            // Excel file
            intent.setDataAndType(uri, "application/vnd.ms-excel");
        } else if (url.toString().contains(".zip") || url.toString().contains(".rar")) {
            // ZIP Files
            intent.setDataAndType(uri, "application/zip");
        } else if (url.toString().contains(".rtf")) {
            // RTF file
            intent.setDataAndType(uri, "application/rtf");
        } else if (url.toString().contains(".wav") || url.toString().contains(".mp3")) {
            // WAV audio file
            intent.setDataAndType(uri, "audio/x-wav");
        } else if (url.toString().contains(".gif")) {
            // GIF file
            intent.setDataAndType(uri, "image/gif");
        } else if (url.toString().contains(".jpg") || url.toString().contains(".jpeg") || url.toString().contains(".png")) {
            // JPG file
            intent.setDataAndType(uri, "image/jpeg");
        } else if (url.toString().contains(".txt")) {
            // Text file
            intent.setDataAndType(uri, "text/plain");
        } else if (url.toString().contains(".3gp") || url.toString().contains(".mpg") || url.toString().contains(".mpeg") || url.toString().contains(".mpe") || url.toString().contains(".mp4") || url.toString().contains(".avi")) {
            // Video files
            intent.setDataAndType(uri, "video/*");
        } else {
            intent.setDataAndType(uri, "*/*");
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }
}


При нахождении совпадения, Используем метод setDataAndType(), чтобы указать Uri и тип MIME для передаваемых данных.



Если файл содержит формат, не рассмотренный нами, то в setDataAndType() в качестве типа указываем “*/*”. Таким образом система покажем нам все установленные на устройстве приложения, чтобы можно было самим выбрать с помощью чего открыть файл.

Windows Phone


Универсальным приложениям для Windows Store/Windows Phone Store практически полностью открыта файловая система, по крайней мере не системные папки. Класс OpenFilePicker позволяет на обеих платформах открывать файлы из любого доступного источника: память устройства, внешние носители и устройства, облака (если установлены соответствующие приложения). В связи с этим каких-либо проблем с открытием файлов на этих устройствах нет, стандартный класс даже позволяет сделать фото через меню выбора файла, что весьма удобно.

Для того, чтобы открыть файлы через стандартный диалог выбора файла, необходимо создать экземпляр класса OpenFilePicker и проинициилировать его несколькими параметрами:
List<string> .FileTypeFilter
— коллекция разрешённых расширений файлов (чтобы позволить выбирать любые файлы, нужно добавить запись "*").
 PickerLocationId .SuggestedStartLocation
— этот перечислимый тип позволяет указать локацию, которая откроется первой в диалоге (например: PickerLocationId.ComputerFolder).
PickerViewMode .ViewMode
— позволяет выбрать тип отображения файлов (список или сетка).

Вызов диалога выбора файла на Windows 8.1 и Windows Phone 8.1 различается, не смотря на универсальный API (как известно, он не на 100% универсальный).

Для Windows 8.1 приложения необходимо вызвать метод .PickMultipleFilesAsync() или .PickSingleFileAsync() в зависимости от того, необходимо выбрать один файл или несколько. Эти методы возвращают соответственно IReadOnlyList<StorageFile> и StorageFile (строго говоря, они возвращают Task, поэтому необходимо использовать async/await).



Для Windows Phone 8.1 всё несколько сложнее. Аналогичные методы называются .PickMultipleFilesAndContinue() и .PickSingleFileAndContinue(). Оба метода ничего не возвращают (void), однако после выбора файлов в диалоге вызывается метод ContinueFileOpenPicker(), который является членом интерфейса IFileOpenPickerContinuable. Этот интерфейс не встроен в стандартный API, однако его можно взять в классе ContinuationManager. Подробнее о том, как продолжить работу после вызова методов *AndContinue(), а также скачать класс ContinuationManager можно здесь. И так, после того как класс ContnuationManager добавлен к проекту по инструкции, необходимо класс, из которого вызывается метод .PickMultipleFilesAsync() или .PickSingleFileAsync(), унаследовать от интерфейса IFileOpenPickerContinuable. Затем нужно реализовать метод void ContinueFileOpenPicker(FileOpenPickerContinuationEventArgs args), где в args.Files содержится коллекция объектов StorageFile.



Открытие файлов из сервиса производится путём сохранения файла на диск во внутреннюю папку приложения и последующим указанием его в методе LaunchFileAsync() класса Launcher. После этого система либо открывает файл приложением по умолчанию для данного типа файла, либо предлагает выбрать приложение из установленных, либо предлагает найти его в магазине.
Tags:том томфайлыфайловая системамобильные приложенияitunes file sharingandroidiOSWindows 8.1Windows phone 8.1
Hubs: Edusty corporate blog Development for iOS Development for Android Development for Windows Phone Development for Windows
+14
19.6k 122
Comments 4
Information
Founded

10 December 2012

Location

Россия

Website

edusty.ru

Employees

2–10 employees

Registered

14 October 2014