• 0
Belov.V.

[Android] Обработка приложением неявного намерения (Intent)

Вопросы

Приложение зарегистрировано для обработки файла по типу через файл манифеста (неявное намерение).

<intent-filter>  
     <action android:name="android.intent.action.VIEW" />
     <category android:name="android.intent.category.DEFAULT" />
     <data android:mimeType="text/xml" />
</intent-filter>

В списке выбора появляется. Как корректно в приложении получить содержание Intent (имя файла, путь)?

Пробовал реализовать через подписку на получение сообщения на изменение статуса приложения:
TMessageManager.DefaultManager.SubscribeToMessage(TApplicationEventMessage, DoApplicationEventChanged);

При этом событие вызвавшее активацию определить можно, но вот как добраться до Intent не пойму:

procedure TForm1.DoApplicationEventChanged(const Sender: TObject; const Message: TMessage);
var
   Intent   : JIntent;
   app_data : TApplicationEventData;
begin
	if not(Message is TApplicationEventMessage) then exit;
	app_data :=  TApplicationEventMessage(Message).Value;
        case app_data.Event of
          FinishedLaunching, BecameActive : ....
        end;                
end;

Что-то застрял я на этом. Как вообще добраться до открывшего приложение Intent? 
Если реализовывать через IFMXApplicationEventService вопрос в итоге такой же.
 
Если есть описание реализации аналогичного функционала для iOS, буду благодарен.
Изменено пользователем Belov.V.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 ответов на этот вопрос

  • 0

Добрый день,

 

Я думаю эта тема вам поможет: [Android] Как в вызываемом приложении получить результат, объект JIntent?

 

Приложение делает широковещательную рассылку с сообщением TMessageResultNotification

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Добрый день,

 

Я думаю эта тема вам поможет: [Android] Как в вызываемом приложении получить результат, объект JIntent?

 

Приложение делает широковещательную рассылку с сообщением TMessageResultNotification

 

Ярослав, спасибо!

 

Эту тему смотрел, но попробую еще раз покрутить. У меня почему то TMessageResultNotification.Value всегда неопределенный возвращался (и оба *Code всегда нулевые). В результате из него ничего, кроме вылетания приложения получить не удавалось.

 

Как минимум, если точно делается широковещательная рассылка TMessageResultNotification направление копания понятно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
Все же путь подписи на получение широковещательную рассылку кмк не верный, т.к. приложение может быть не запущено, а событие в системе уже произошло (к примеру проводится вызов для обработки файла, полученного по почте, а приложение на событие не подписано, т.к. на момент вызова не запущено).
 
В любом случае проверил - приложение активируется (или запускается, или выводится из бека), т.к. зарегистрировано через <intent-filter>. При этом рассылка TMessageResultNotification не поступает.
 
Приведенный выше пример о другом - это вариант обмена данными между своими приложениями. Возможно я что-то не так понимаю. :-(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Вопрос в продолжение темы.

Добрался до получении файла или пути к нему:

var 
  uri     : Jnet_Uri;
  uriStr  : String;
....
begin
...
    if TJIntent.JavaClass.ACTION_VIEW.equals(intent.getAction) then
    begin
      uri := intent.getData;
      uriStr := JStringToString(intent.getData.getEncodedPath);
 

Не могу вытащить содержимое. Из uri или uriStr разными способами getPath, toString или через JURIToStr() ) можно вытащить строку двух видов (для примера событие активировалось из почтового приложения):

      content: //...../messages/2687/attachments/0.1/BEST/false
      или
      /<почтовый профиль>/messages/2687/attachments/0.1/BEST/false 

Ни пути ни такого файла из приложения не находится. Extras тоже пустой.

 

Как из intent.getData получить контент? Кто мысль подкинет.?

Изменено пользователем Belov.V.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

К теме о подписки на это сообщение. В какой момент осуществляете подписку?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

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

Регистрация на обработку файла по типу через <intent-filter> в AndroidManifest.xml

 

Как писал выше, метод через подписку не сработает, если приложение на момент создания Intent системой не было запущено. Полную реализацию обязательно выложу, вот только бы до файла добраться.

Изменено пользователем Belov.V.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Вот по такому принципу http://stackoverflow.com/questions/10386885/intent-filter-intent-getdata-returns-null

Но у меня Extras пустой JBandle возвращает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Регистрируем намерение через файл манифеста (ниже для файлов с типом xml). Для Android 3.2 адекватнее работал второй фильтр:

<activity …
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
	<data android:scheme="file" />
	<data android:mimeType="text/xml" />
	<data android:mimeType="application/xhtml+xml" />
</intent-filter>
<!-- Для 3.2 -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
	<category android:name="android.intent.category.DEFAULT" />
	<data android:scheme="file" />
	<data android:mimeType="*/*" />
	<data android:host="*" />
	<data android:pathPattern=".*\\.xml" />
	<data android:pathPattern=".*\\..*\\.xml" />
	<data android:pathPattern=".*\\..*\\..*\\.xml" />
	<data android:pathPattern=".*\\..*\\..*\\..*\\.xml" />
	<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.xml" />
</intent-filter>

Регистрируем свой обработчик события для на событие смены состояния приложения:

procedure TForm1.FormCreate(Sender: TObject); 
var
  ApplicationService: IFMXApplicationEventService;
begin

  if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, ApplicationService)
  then ApplicationService.SetApplicationEventHandler(ApplicationEventChanged);

end;

Оформляем обработчик.

Получение файла можно перенести в Form1.onCreate, но я для экспериментов с activity делал тут:

function TForm1.ApplicationEventChanged(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
var
    intent        : JIntent;
    fileFullPath  : String;

begin
  intent := SharedActivity.getIntent;

  // BecameActive
  if AAppEvent = TApplicationEvent.BecameActive then
  begin
    if Assigned(intent) and TJIntent.JavaClass.ACTION_VIEW.equals(intent.getAction) then
    begin
        fileFullPath := JStringToString(intent.getData.getPath);
        if FileExists(fileFullPath) then
        begin
          // обработка файла fileFullPath
          // ...
        end;
    end;
  end
  // завершаем Activity при переводе приложения в "Background"
  else if AAppEvent = TApplicationEvent.EnteredBackground then SharedActivity.finish;
  //

  Result := True;
end;
Хочу обратить внимание, что привел только сам принцип. Очень важно корректно завершить активность (при сворачивании приложения, отключении экрана и т.д. ), т.к. при повторном вызове активности будет вызываться последний из стека.
И если его не закрывать будем получить предыдущий, не закрытый activity. А если за приложением зарегистрировано несколько Activity (приложение можно вызвать из ланчера или как в примере, для обработки файла по типу).... в общем тут есть с чем поиграться.
 
Для желающих посмотреть поведение и последовательность выкладываю пример, который формирует лог обработки.
Нужно закоментировать:
   else if AAppEvent = TApplicationEvent.EnteredBackground then SharedActivity.finish;
И посмотреть что и когда приложение получает в SharedActivity и AAppEvent.
 
 
 
Что не получилось:
1) Некоторые программы отдают файл в схеме «content» (к примеру Gmail v5.1 отдает). Как в этом случае получить содержание файла не разобрался. Поэтому в фильтре ограничил вид контента "file"
2) Не смог добраться до стека Activity. Если приложение в памяти и повторно вызывается с новой activity - возможно вот тут это могло пригодиться. (activity ... android:launchMode="singleTop" в этом случае не помог).
 
ADD: было обсуждение, кто как закрывает приложения на андроид, чтобы не оставалось в памяти. Если добавлять SharedActivity.finish приложение 100% убирается из памяти.
 

 

Intent_Get-File.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Что не получилось:

1) Некоторые программы отдают файл в схеме «content» (к примеру Gmail v5.1 отдает). Как в этом случае получить содержание файла не разобрался. Поэтому в фильтре ограничил вид контента "file"

Для получения «content» я сделал так

 

var
  Intent: JIntent;
  Uri: Jnet_Uri;
  INStream: JInputStream;
  OUTStream: JOutputStream;
  outputfile: string;
  FFF: JFile;
  NumRead, NumWritten: Longint;
  Buffer: TJavaArray<Byte>;
begin
...
        Intent := SharedActivity.getIntent;
        if (Pos('image/', JStringToString(Intent.getType))>0) or
          (Pos('audio/', JStringToString(Intent.getType))>0) or
          (Pos('video/', JStringToString(Intent.getType))>0) or
          (Pos('application/', JStringToString(Intent.getType))>0)    or
          ('*/*' = JStringToString(Intent.getType)) then
        begin
          if JStringToString(Intent.getType) <> '' then
          begin
            Parcel := Intent.getParcelableExtra(TJIntent.JavaClass.EXTRA_STREAM);
            Uri := TJnet_Uri.Wrap(Parcel);

              if JStringToString(Uri.getScheme) = 'content' then
              begin
                if Pos('/mpeg', JStringToString(Intent.getType)) > 0 then
                  outputfile := 'my.mp3'
                else
                  if Pos('/jpeg', JStringToString(Intent.getType)) > 0 then
                    outputfile := 'my.jpg'
                  else
                    outputfile :=  'my.' + copy(JStringToString(Intent.getType), Pos('/', JStringToString(Intent.getType))+1, 
                       Length(JStringToString(Intent.getType)));//выдергиваем имя типа для того чтобы сделать его расширением
                //на случай если в Intent не уточнен тип, а указана *, например image/*  
	        if Pos('.*', outputfile) > 0 then
                  outputfile := StringReplace(outputfile, '.*', '.tmp', [rfReplaceAll]);

                Buffer := TJavaArray<Byte>.Create(4096);
                INStream := SharedActivityContext.getContentResolver.openInputStream(Uri);
                try
                    FFF := TJFile.JavaClass.init(StringToJString(<ИМЯ_ПАПКИ>), StringToJString(outputfile));
                    FFF.setWritable(true, false);
                    OUTStream := TJFileOutputStream.JavaClass.init(FFF);
                    repeat
                      NumRead := inStream.read(buffer);
                      if (NumRead <= 0) then
                        Break;
                      outStream.write(buffer, 0, NumRead);
                      application.ProcessMessages;
                    until NumRead <= 0;
                    outStream.close;
                    inStream.close;
                except
                  on e: exception do
                    raise Exception.CReate('Error. Can''t copy file');
                end;
              end
          end
        end
end
может не самое оптимальное, но работает, в итоге у вас файл с именем outputfile и в папке <ИМЯ_ПАПКИ>

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Похожий контент

    • От gutalin79
      Почему при добавлении MapView в пример Android Service, приложение перестает работать?
      AndroidSimpleService.zip
       
       
       
      Пример делал по этому видео: 
       
    • От Astghik
      Hello !!!
      I want onButtonClick create popup. I use TPopup component. All good, but on android "Back button" click closing forma. But I want close popup (when popup is shown).

       
      //---------------------------------------------------------------------------------
      void __fastcall  btn3PointsClick(TObject *Sender)
      {
          PopUpSettings->IsOpen = true;
          PopUpSettings->PlacementTarget = btn3Points;
          PopUpSettings->BringToFront();
      }
      //-------------------------------------------------------------------------------------
      void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose)
      {
          try {
              if (PopUpSettings->IsOpen == true) {
                  CanClose = false;
              }
              else {
                  CanClose = true;
              }
          } __finally {
              PopUpSettings->IsOpen = false;
          }
      }
      //-------------------------------------------------------------------
       
    • От Rokweb
      Таймер с интервалом 1мс заметно подтормаживает во время выполнения анимации TFloatAnimation в Tokyo. У всех так или только у меня?
    • От Rokweb
      Здравствуйте.
      Речь пойдёт об Android.
      Использовал в Berlin данный unit для проигрывания звуков (TMediaPlayer не подходит) и все отлично работало. Сейчас перешел на Tokyo и происходит зависание в цикле:
       
      while not GLoaded do begin Sleep(10); Application.ProcessMessages; end;  
      Модуль прикрепил в сообщении.
       
      Так же интересует - возможно ли, использовать стиль, созданный в процессе разработки Android приложения - в iOS и если да - то как это правильно реализовать (почти каждый контрол имеет сейчас свой стиль)?
       
      Прошу помощи.
      GameAudioManager.zip
    • От zekelive
      Товарищи, здравствуйте. Хотел бы проконсультироваться с вами на довольно сложно для меня тему. Имеется клиентское мобильное приложение на Андроид. Принцип его просто, загружает фирмы из БД в scrollbox. За счёт того, что сразу загрузка всех данных из сервера занимает длительное время, было принято решение загружать с сервера только ключевую информацию (название фирмы), а остальную информацию загружать из локальной БД. При этом, т.к. файл БД можно легко вытащить из apk файла любому человеку, размещать всю БД на локалке нельзя. Только информацию в целом не представляющую большой значимости в отдельности от названия фирмы и не только. 
      Вопрос, правильная ли схему построения была выбрана с точки зрения защиты данных (если это так можно назвать), и оптимизации загрузки информации. 
      Приветствуются ваши советы, как лучше построить схему взаимодействия приложения с БД, или как лучше защитить данные. В идеале для быстродействия, загнать побольше данных в локальную БД. 
    • От Edward Tarasov
      Привет всем. кто сталкивался с такой ерундой, что в webbrowser вместо сайта тупо белый экран?? причем сам сайт отображаеться норм, и на том же планшете, но в стандартном бразуере и на компе... и именно этот сайт не пашет из приложения
    • От fredhack
      Доброго времени суток подскажите пожалуйста как мне получить ссылку из браузера запущенного через intent в общем суть такова:
      1 запускаю браузер через интент с сылкой http://fire-monkey.ru
      2 на ссылке происходит редирект
      3 я попадаю на http://fire-monkey.ru/forum/
      Как получить последнюю ссылку после редиректа? в данном случае она равна http://fire-monkey.ru/forum/
      var Intent: JIntent; begin Intent := TJIntent.Create; Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.setData(StrToJURI('http://fire-monkey.ru')); SharedActivity.startActivity(Intent); end;  
    • От zekelive
      Друзья, первый раз столкнулся с картами и не пойму в чем дело. Приложение подписано, релизная версия. Добавил карты на форму и запустил на компиляцию, все отлично. Запускаю на смартфоне - приложение сразу вылетает. Ничего не прописывал связанное с картами, просто добавил компонент на форму. Что не так ?
    • От Алексей Алексеев
      Здравствуйте! Помогите начинающему, всё перелазил, всё что мог и всё безрезультатно.
      Такая проблема: 
      Стоит задача убрать перенос строки в Memo:
      Из 
      "1строка"
      "2строка" 
      сделать:
      "1строка 2строка" .
      Казалось бы все просто:
      memo1.Text:=memo1.Text.Replace(#13#10,' '); И на Windows всё работает, но на Android отказывается!
      Просто не реагирует, ошибок не выдает. Проверял на XE8 и на 10.2.
      Может дело в смартфоне Xiomi miMax? Так как вообще memo на нём глючит...
    • От gutalin79
      Доброго времени суток!
      Хотел у Вас спросить. Есть ли возможность сделать на Delphi под Android кнопку которая была бы доступна в режиме блокировки? То есть чтобы я мог её нажать и включить фонарик или ещё что-нибудь и при этом не пришлось разблокировать телефон. Заранее благодарю, за ответ!  

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу