понедельник, 12 мая 2014 г.

Intent: Open File или как открыть файл в приложении по умолчанию

Частенько на разных форумах всплывают вопросы об открытии файлов в приложении (ях) по умолчанию. Решил разъяснить немного ситуацию. Про сами Intent рассказывать не буду, т.к. есть очень хорошая статья (Delphi XE5: использование Intent (намерения) в Android), в которой объясняется принцип работы с интентами и имеется парочка примеров, остальные подробности вы всегда можете найти в справке Android API.









Если вам требуется открыть/запустить какой либо файл, то вам необходимо воспользоваться Интентом.

Пример №1 – откроем картинку «picture.png», которая лежит в папке «Download»
uses
  System.IOUtils, FMX.Helpers.Android, Androidapi.Helpers,
  Androidapi.JNI.GraphicsContentViewText;

procedure TForm1.Button1Click(Sender: TObject);
var
  Intent: JIntent;
begin
  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
  Intent.setDataAndType(StrToJURI('file:' + TPath.Combine(TPath.GetSharedDownloadsPath, 'picture.png')), StringToJString('image/png'));
  SharedActivity.startActivity(Intent);
end;

Самая интересная строка:
Intent.setDataAndType(StrToJURI('file:' + TPath.Combine(TPath.GetSharedDownloadsPath, 'picture.png')), StringToJString('image/png'));

В этой строке мы указываем:
  • полный путь до файла, при этом, не забывая добавить в начало 'file:', без этого Android не поймет, что вы открываете файл
  • вторым параметром идёт указание MIME Type (ниже вы найдёте список самых популярных типов, а также вариант с автоматическим определением)

Также можно указывать неполный MIME тип, например, так «image/*», «video/*» и т.п.

Таблица соответствия «расширение = MIME Type»:
Расширение MIME Type
Android Application .apk application/vnd.android.package-archive
Text .txt text/plain
.csv text/csv
.xml text/xml
Web related .htm text/html
.html text/html
.php text/php
Image .png image/png
.gif image/gif
.jpg image/jpg
.jpeg image/jpeg
.bmp image/bmp
Audio .mp3 audio/mp3
.wav audio/wav
.ogg audio/x-ogg
.mid audio/mid
.midi audio/midi
.amr audio/AMR
Video .mpeg video/mpeg
.3gp video/3gpp
Package .jar application/java-archive
.zip application/zip
.rar application/x-rar-compressed
.gz application/gzip


В Google уже позаботились об определении MIME типов и создали карту «расширение = MIME type»(Android API: android.webkit.MimeTypeMap ), нам остаётся только воспользоваться ей, а точнее её методами. 
Для того, чтобы методы работали, необходимо добавить в uses модуль: «Androidapi.JNI.Webkit»

Шаги:
  1. Получаем расширение файла (без точки)
  2. Получаем экземпляр карты
  3. Получаем MIME type

Пример №2с автоматическим определением MIME Type по расширению файла.
uses
  System.IOUtils, FMX.Helpers.Android, Androidapi.JNI.JavaTypes,
  Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Webkit;

procedure TForm1.Button1Click(Sender: TObject);
var
  ExtFile: string;
  mime: JMimeTypeMap;
  ExtToMime: JString;
  Intent: JIntent;
begin

  ExtFile := 'png';
  mime := TJMimeTypeMap.JavaClass.getSingleton();
  ExtToMime := mime.getMimeTypeFromExtension(StringToJString(ExtFile));

  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
  Intent.setDataAndType(StrToJURI('file:' + TPath.Combine(TPath.GetSharedDownloadsPath, 'picture.png')), ExtToMime);
  SharedActivity.startActivity(Intent);
end;


На этом всё. Спасибо за внимание.

21 комментарий:

  1. Спасибо.
    Если моя программа запустила какое-то стандартное приложение на андроиде, то как его потом можно закрыть?

    ОтветитьУдалить
    Ответы
    1. Допустим, вы открыли картинку в стандартной галерее, эта галерея будет открыта поверх вашего приложения, значит, чтобы закрыть её и вернуться в ваше приложение, достаточно нажать кнопку "назад".

      Удалить
  2. >достаточно нажать кнопку "назад"

    Моя программа запускает стороннее андроид приложение. Мне надо чтобы по таймеру моя же программа могла бы и закрыть открытое приложение, без участия человека.
    Спасибо.

    ОтветитьУдалить
    Ответы
    1. Данный вопрос я ещё не рассматривал.
      1. Можно попробовать убить процесс определённого приложения.
      2. Можно попробовать закрыть приложение при помощи «finishActivity»

      В общем надо смотреть справку и думать ;) Да и информации надо больше…

      Удалить
  3. >Да и информации надо больше

    Вся информация по программе довольно проста.
    Например, в 9 часов утра запустить на воспроизведение видео файл. В 9.30 закрыть плеер и запустить его с новым другим видео файлом и т.д. Запуск по расписанию.
    Мне пока не удалось найти ответ как будет выглядеть код закрытия к примеру плеера.

    Распишите, пожалуйста поподробнее Ваши два пункта в плане кода.
    Спасибо.

    ОтветитьУдалить
    Ответы
    1. А закрывать плеер обязательно? Если вы запускаете его из своего приложения и не закрываете плеер, то при очередном запуске плеера, он в теории должен просто запустить другой видео файл, такого не происходит? Каким образом у вас организованно расписание?

      Удалить
    2. >то при очередном запуске плеера, он в теории должен просто запустить другой видео файл,

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

      >Каким образом у вас организованно расписание?

      По таймеру SharedActivity.startActivity(Intent); Данные (время-имя файла) читаются из текстового файла.
      По умолчанию плеером для воспроизведения видео назначен МХ плеер для андроида скаченный из маркета.

      Удалить
    3. Судя по всему, закрыть другое приложение нельзя без системных прав. Завершать можно процессы, принадлежащие вашему приложению.

      Можете попробовать использовать killBackgroundProcesses, но я почти на 100% уверен, что не получится закрыть чужое приложение http://developer.android.com/reference/android/app/ActivityManager.html#killBackgroundProcesses(java.lang.String)

      По поводу вашей ситуации:
      1) А ваше приложение не закрывается автоматически? (Обычно Android завершает приложения сам)
      2) Зачем столько сложностей с запуском стороннего плеера, почему не добавить в ваше приложение функции плеера (воспроизведения видео)?
      3) Можно ещё попробовать использовать AlarmManager - http://developer.android.com/reference/android/app/AlarmManager.html

      Удалить
  4. Большое спасибо.

    >Судя по всему, закрыть другое приложение нельзя без системных прав.

    Root права на устройствах с андроид присутствуют.

    >Зачем столько сложностей с запуском стороннего плеера,

    Воспроизведение видео зациклено. МХ плеер с его возможной программной настройкой воспроизведения видео в режиме повтора, показал лучшие результаты, на закупленных андроид устройствах iconBIT Movie 3D IPTV. Другие плеера на этих устройствах, при воспроизведении видео по кругу в момент перехода видео от конца к началу делали паузу в секунду, и появлялся черный экран. Это было недопустимо т.к. необходим был показ рекламы четко и без рывков и черных кадров при переходе от конца к началу. МХ плеер показал приемлемый результат на iconBIT Movie 3D IPTV.

    > 1) А ваше приложение не закрывается автоматически?

    Мое приложение должно работать круглые сутки и отображать видео по расписанию. Если видео файлов было открыто много, андроид просто выгрузит мое приложение из памяти, что не приемлемо.

    > 2) почему не добавить в ваше приложение функции плеера

    Надо попробовать, но даст ли это такой необходимый приемлемый результат, который показал МХ плеер не известно. Скорее всего, нет т.к. другие плеера не справились. У всех них была секундная пауза с черным экраном перезагрузки от конца к началу видео.
    Связка iconBIT Movie 3D IPTV + МХ плеер дает нужный результат.

    ОтветитьУдалить
  5. >почему не добавить в ваше приложение функции плеера (воспроизведения видео)

    Подскажите, пожалуйста, пример воспроизведения функций плеера в собственном приложении.

    ОтветитьУдалить
    Ответы
    1. В демках есть пример:
      C:\Users\Public\Documents\Embarcadero\Studio\14.0\Samples\Object Pascal\Mobile Snippets\VideoPlayback
      Посмотрите справку по MediaPlayer'у.

      Удалить
    2. Если был о бы всё так просто:) TMediaPlayer не везде воспроизводит видео, с чем связано не понятно...

      Удалить
  6. Задачка "неизвестного" настолько проста что тут нет необходмости писать свою программу, проще использовать Tasker, она и не выгрузиться и "убъет" и рассписание настроит.
    https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm&hl=ru
    или аналог
    https://play.google.com/store/apps/details?id=AutomateIt.mainPackage&hl=ru

    ОтветитьУдалить
  7. Может в этих программах и можно настроить запуск видео из нужной папки по расписанию, правда при первом прочтении описания не понятно пока как это сделать.
    При наличии своей же программы, мне или пользователю достаточно отредактировать под свои нужды текстовый файл и это все. Не надо проводить никакие обучающие курсы. :)
    Пример такого INI файла:
    [ЗАВТРАК]
    time = 09:00:00
    name = завтрак.mp4

    [ЛАНЧ]
    time = 12:00:00
    name = ланч.mp4

    и т.д.

    А если в интерфейс программы добавить логотип ресторана, то вообще выглядит весьма привлекательно для заказчика. :)

    ОтветитьУдалить
  8. А можно добавить свою программу в этот список?

    ОтветитьУдалить
    Ответы
    1. Чтобы зарегистрировать приложение в качестве потенциального обработчика намерений, нужно добавить тег в узел компонента в манифесте.

      Удалить
    2. Упс, парсер съел тег :) Вот этот тег "intent-filter".

      Удалить
  9. А можно более подробный гайд для ACTION_SEND? Через ActionList и стандартные Action-ы все работает хорошо, но как сделать для более сложных файлов?

    ОтветитьУдалить
  10. Всё таки мне интересен вопрос нормального воспроизведения видео файлов через MX плеер! Т.к. стандартный FMX компонент не хочет воспроизводить картинку в видео (только звук). Добился воспроизведение через MX плеер, но при запуске нового файла, предидущий не убивается, как можно убрать процес? или как можно отледить что процес завершился? Потому что по завершенияю процеса плеер сам закрывается

    ОтветитьУдалить
  11. а никто случаем не знает как открыть галерею для выбора НЕСКОЛЬКИХ картинок и на выходе получить список файлов?

    ОтветитьУдалить