• 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 и в папке <ИМЯ_ПАПКИ>

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


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

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

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

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

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

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

Войти

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

Войти


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

    • От zekelive
      Добрый день, товарищи. Если кто сталкивался, подскажите) в потоке создаются картинкив виде плиток и прочие компоненты и падают на scrollbox.  Но в runtime пролистывание лагает, да в целом вся программа подлагивает. Можно ли как то реализовать подгрузка в фоне без ущерба? Или может ещё какой способ есть?
    • От Вольдемар
      Пользуюсь в своем Android приложении этим компонентом, вроде всё работает. Но хотелось бы асинхронности. Помогите пожалуйста с примером, как сделать асинхронность и получать результат после Post. Спасибо
    • От Aptyp
      На моём Samsung Note 5 вокруг букв проглядываются линии. Причём пробовал 3 различных разрешения экрана, ничего не меняется. У друга на Xiaomi Redmi 4x такого не наблюдается.
      Что это может быть?
       


    • От om.pranayama
      Здравствуйте форумчане и профессионалы разработчики.
      Компилирую проект через C++Builder 10.2  под Android
      Появилась следующая проблема при использовании компонента TBitmapListAnimation
      Если приложение свернуть, а затем развернуть - то появляются жуткие глитчи в ввиде чёрных фонов вокруг компонентов, типа TImage, TButton.
      В Windows такая проблема - не наблюдается.
      Попытки вызвать Repaint или даже Invalidate для всей формы - положительного результата не дают.
      Пожалуйста, помогите решить эту проблему.
      //--------------------------------------------------------------------------------------------------------------------------------------------
      ТЕМУ МОЖНО УДАЛЯТЬ
      Причина не в TBitmapListAnimation а в TAniIndicator, который работал совместно с TBitmapListAnimation.
      Приношу извинения за беспокойство. Проблема была в TAniIndicator. Буду разбираться почему он так себя безобразно ведёт.
      Тему можно удалять.
    • От Aptyp
      В приложении:
          procedure TForm7.Button1Click(Sender: TObject);     var AIntent: JIntent;         AServiceName: string;     begin       AIntent := TJIntent.Create;       AServiceName := 'com.embarcadero.services.Service';       AIntent.setClassName( TAndroidHelper.Context.getPackageName(), TAndroidHelper.StringToJString( AServiceName ) );       AIntent.putExtra( TAndroidHelper.StringToJString( 'Code' ), 0 );       AIntent.putExtra( TAndroidHelper.StringToJString( 'Data' ), TAndroidHelper.StringToJString( 'DataString' ) );       TAndroidHelper.Activity.startService( AIntent );     end;
      В сервисе:
          procedure TDM.AndroidIntentServiceCreate(Sender: TObject);     begin       Toast( 'Create' );     end;          procedure TDM.AndroidIntentServiceHandleIntent(const Sender: TObject;       const AnIntent: JIntent);     begin       Toast( 'HandleIntent' );     end; Сообщение 'Create' показывается, а 'HandleIntent' нет. OnCreate срабатывает, но onHandleIntent не вызывается что бы я не делал. Может я что-то не так делаю?
    • От Roman V
      Всем привет. Учусь работать с ini-файлами на Android. И сразу же возникла проблема, которую никак не могу решить. Хотел написать подобие приложение-тест с хранением данных в ini файле. В итоге все отлично работает на windows,а под Андроид при запуске висит только значок firemonkey секунд 10 и приложение вырубается так и не запустившись. В чем может быть проблема? Использую отладку по USB. 
      TIniFile *Ini = new TIniFile(System::Ioutils::TPath::GetDocumentsPath() + PathDelim + "options.ini"); Юзаю эти библиотеки 
      #include <System.IOUtils.hpp> #include <System.IniFiles.hpp>  
    • От A. Sharif
      Возможно ли с помощью intent получить от какого-либо из официальных приложений Вконтакте/Фейсбук/Инст/Google access-token (через кол-бэк метод)?
      Предусматривается ли данная возможность этими приложениями? Если кто делал - приведите, пожалуйста, пример получения результата. 
    • От Wovan2
      Здравствуйте.
      Пишу на Delphi 7. И все было нормально пока не у нас не появился терминал сбора данных на Androide. На Delphi 10 написал простенькое приложение. Но тут встала проблема с занесением данных в поле ввода со сканера штрихкода. В инете нашел, что это дело просто решается интентами. Вообще в windows я подобное делал: вешал процесс, следящий за com-портом, и при появлении данных на нем пересылал их куда надо. В Android должно быть не сложнее. Но я запутался во всей этой куче параметров и функций, передаваемых и получаемых "намерениями".
      В общем вот что мы имеем на данный момент.
      В настройках сканера прописано:
       
      Intent output - android.intent.ACTION_DECODE_DATA Intent string extra - barcode_string На просторах нашел запуск BroadcastReceiver.
      На событие получения сообщения повесил 
      ed.Text := JStringToString(csIntent.getExtras.getString(TJIntent.JavaClass.EXTRA_INTENT)); где csIntent параметр из  BroadcastReceiverOnReceive(csContext: JContext; csIntent: JIntent); Но ничего не выходит. 
      Я подозреваю, что данные из сканера где-то в структуре csIntent. Но, к сожалению, в отладке дальше адреса этой переменной пробраться не получилось.
      Причем строка ed.Text := JStringToString(csIntent.getAction); возвращает в Text название интента: "android.intent.ACTION_DECODE_DATA".
      Помогите разобраться со структурой JIntent. Спасибо.
       
       
    • От gonzales
      Доброго времени суток!
      Решаю следующую задачу, в приложении динамически формируются разные объекты, наследники от одного класса. При формировании объектов заполняется динамический массив этих элементов. Далее я хочу в отдельном потоке для каждого из элементов массива получить его состояние, то есть делаю запрос к серверу. Все это повешено на таймер, каждую секунду должен отрабатываться запрос. Все более менее работает в Windows, а на Андроиде со временем приложение валится. Вот код таймера, для читаемости я удалил куски с различными вариантами E. RootElements - это массив TEssense от которого есть наследники. Функции GetBoardCurrentValue, GetBoardMaxValue - по сути запросы к серверу. 
      Подскажите, правильно ли я оформляю работу с потоками для работы на Андроиде?
      procedure TForm1.MasterTimerTimer(Sender: TObject); begin TTask.Run( procedure var l, d, a: byte; i,j:integer; E: TEssence; p: Pointer; VirtualNode: IXMLNode; VirtualElementNode: IXMLNode; id: byte; begin l := Length(Form1.RoomElements); for j := 0 to l - 1 do begin E := Form1.RoomElements[j]; // Реле if E is TRele then begin d := (E as TRele).Device_ID; a := (E as TRele).Device_Adress; if Form1.GetBoardCurrentValue(d, a) = true then begin TThread.Synchronize(nil, procedure begin (E as TRele).ReleSwitch.IsChecked := Form1.device[d].Board[a].CurrentValue.ToBoolean; end); end; // (E as TRele).ReleOnTimer(E) end // Диммер else if E is TDimmer then begin d := (E as TDimmer).Device_ID; a := (E as TDimmer).Device_Adress; if Form1.GetBoardMaxValue(d, a) = true then begin TThread.Synchronize(nil, procedure begin if (Form1.device[d].Board[a].Type_ID = TType.Светодиод) or (Form1.device[d].Board[a].Type_ID = TType.Диммер220) then begin (E as TDimmer).DimmerValue.Text := (Form1.device[d].Board[a].MaxValue).ToString; end; end); end; // (E as TDimmer).DimmerOnTimer(E) end // Таймер else if E is TSTimer then begin id := (E as TSTimer).STimerIndex; Form1.FillHTTPRequest(0, 0, HTTP_GET_TIMER_INFO, id); if Form1.AnswerIsComming = HTTP_GET_TIMER_INFO then begin TThread.Synchronize(nil, procedure begin if Form1.HTTPAnswer.Data1 = 0 then (E as TSTimer).Interval.Text := 'OFF' else (E as TSTimer).Interval.Text := 'ON' end); end; // (E as TSTimer).STimerOnTimer(E); end; end; end); end;   
    • От andahay
      Доброго времени суток. Есть android приложение, в нем есть диалоговое окно, которое предлагает перейти в google play и скачать другое приложение (pro версию), с 2 кнопками (да/нет). Как реализовать этот переход в Google play, чтобы в нем сразу было загружено нужное приложение. Использую Delphi XE7
  • Последние посетители   0 пользователей онлайн

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