пятница, 3 апреля 2015 г.

App Tethering #1: Поиск и подключение к удалённым приложениям

Решил рассмотреть эту технологию поближе...

App Tethering в RAD Studio – это компоненты, позволяющие приложениям взаимодействовать друг с другом на одном компьютере, по сети и на разных платформах.







Список статей:

p.s. Все права на картинку принадлежат Embarcadero Technologies, Inc.


Возможности данной технологии  очень широки. Её можно использовать в большом количестве сфер (авто, торговля, промышленность и т.д.), также можно значительно упростить организацию системы «Умный дом» или создать приложение, с помощью которого можно  управлять основным приложением, установленным на ноутбуке. Или написать игру, в которой будет реализован Мультиплеер.

App Tethering – использует модель обмена информацией «peer-to-peer». Т.е. каждое подключённое устройство/приложение может выступать одновременно в роли «Клиента» и «Сервера». Подключаться можно посредством локальной сети, Wi-Fi или Bluetooth (работает только на Windows, Mac и Android).

Сразу скажу, что с RAD Studio поставляется 4 примера использования данных компонентов, найти их можно тут «C:\Users\Public\Documents\Embarcadero\Studio\15.0\Samples\Object Pascal\RTL\Tethering».

Общая, техническая информация.
Приложения, использующие  компоненты App Tethering могут видеть друг друга на одном устройстве, в локальной сети, по Wi-Fi и Bluetooth.

Способы подключения:
  • Автоматический режим 
  • Ручной режим 
Чтобы избежать подключения сторонних (не доверенных) приложений, можно и нужно установить пароль на подключение (свойство Password у компонента TetheringManager).

При подключении, есть возможность указать определённую цель, прописав IP адрес.

Менеджеры подключения хранят информацию о подключении в течение текущей сессии. Поэтому, если вдруг была потеряна связь между приложениями, например по причине недосягаемости, то в момент, когда приложения/устройства будут в пределах досягаемости друг друга, подключение произойдёт автоматически (без запроса пароля). Также имеется возможность постоянного хранения (в виде локального файла) информации о подключении.

С помощью App Tethering можно:
  • Запускать действия удалённо.
  • Передавать данные стандартных типов и потоки
Теперь рассмотрим всё это более подробно…

Для того чтобы использовать все возможности App Tethering, необходимо разместить на форме два компонента «TTetheringManager» и «TTetheringAppProfile». Ниже рассмотрим базовые свойства и события этих компонентов, после чего попробуем использовать их в нашем тестовом приложении.

TTetheringManager  - компонент, отвечающий за подключение. Позволяет обнаружить и соединиться с другими менеджерами, которые в свою очередь предоставляют доступ к удалённым профилям (компонент TetheringAppProfile). Может быть связан с одним или более профилями, одним или более адаптерами, и одним или более протоколами.

TTetheringAppProfile – компонент, отвечающий за обработку данных. Определяет, какие данные будут доступны удалённым профилям, а также обрабатывает данные приходящие с удалённых профилей.

Теперь попробуем соединить два приложения и вывести информацию о соединении.
Соединим приложения в автоматическом режиме, а потом уже рассмотрим ручной режим соединения.

Автоматический режим соединения.
Для начала создаём два проекта, первый назовём «Server», второй «Client». Такие названия я выбрал для наглядности. Теперь, в каждом проекте добавляем на форму компоненты «TTetheringManager» и «TTetheringAppProfile» и изменяем свойства (дублируя):


TTetheringManager
  • AllowedAdapters: Network – выбираем тип подключения
  • Enabled: True 
  • Password: 12345 – Устанавливаем пароль на подключение
  • Name и Text: TMServer и TMClient – это имя менеджера для каждого проекта, оно будет отображаться в информации о подключении
TTetheringAppProfile
  • Enabled: True 
  • Group: TestTethering – это свойство определяет группу профилей, которые будут автоматически соединяться
  • Manager – выбираем менеджер, который лежит на форме рядом профилем
  • Name и Text: TAPServer и TAPClient – это имя профиля, будет отображаться при запросе списка доступных профилей
На этом настройка завершена.

Теперь для наглядности добавим несколько компонентов, которые помогут нам определить, удалось ли установить соединение между приложениями. В каждом проекте положим на форму: 1 – TLabel, 1 – TMemo.

Результат будет примерно такой:


Далее в коде пропишем:
  • Обработчик для события FormShow у формы
  • Три обработчика событий для компонента «TTetheringManager»: OnPairedFromLocal, OnPairedToRemote, OnRequestManagerPassword.
Сразу опишу эти события:
  • OnPairedFromLocal – срабатывает, когда удалённый менеджер успешно соединился с локальным (позволяет получить информацию о подключении)
  • OnPairedToRemote – срабатывает, когда локальный менеджер успешно соединился с удалённым (позволяет получить информацию о подключении)
  • OnRequestManagerPassword – срабатывает, когда для подключения требуется ввод пароля (прим. Если просто указать свойство Password и не писать обработчик для этого события, то соединение не происходит. Возможно проблема у меня в среде разработки(XE7). По этой причине, приходится писать обработчик для события и указывать в открытом виде пароль.)
Чтобы инициировать автоматическое подключение, необходимо вызвать метод «AutoConnect» у компонента «TTetheringManager».

Код для проекта «Client» (для проекта «Server» идентичный, только вместо «Client» необходимо написать «Server»):
procedure TForm1.FormShow(Sender: TObject);
begin
  Label1.Text := 'Local Manager: ' + TMClient.Identifier;
  TMClient.AutoConnect();
end;

procedure TForm1.TMClientPairedFromLocal(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  Memo1.Lines.Add('PairedFromLocal: ' +
      AManagerInfo.ManagerIdentifier + ' ' +
      AManagerInfo.ManagerText);
end;

procedure TForm1.TMClientPairedToRemote(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  Memo1.Lines.Add('PairedToRemote: ' +
      AManagerInfo.ManagerIdentifier + ' ' +
      AManagerInfo.ManagerText);
end;

procedure TForm1.TMClientRequestManagerPassword(const Sender: TObject;
  const ARemoteIdentifier: string; var Password: string);
begin
  Password := '12345';
end;


Запускаем оба приложения и видим результат:

Исходники примера: Скачать с Google Drive

Ну вот, теперь мы умеем настраивать автоматическое подключение. Как видите, ничего сложного в этом нет.

Давайте посмотрим, как же нам подключаться в ручном режиме.

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

Для того чтобы выполнить соединение, нам необходимо выполнить три простых шага:
  1. Вызываем метод «DiscoverManagers» у компонента «TTetheringManager», данный метод позволяет найти все доступные менеджеры. После завершения работы данного метода происходит событие «OnEndManagersDiscovery».
  2. Читаем список обнаруженных менеджеров и вызываем метод «PairManager» у компонента «TTetheringManager» указав при этом менеджера, с которым хотим соединиться. Каждый раз, когда мы соединяем свой менеджер с удалённым, происходит событие «OnEndProfilesDiscovery».
  3. Читаем список доступных профилей и вызываем метод «Connect» у компонента «TTetheringProfile» указав при этом профиль, с которым хотим соединиться.
Давайте попробуем реализовать эти шаги в коде.

Скопируем предыдущий пример и внесём в него некоторые изменения:
  • Сохраним весь код из предыдущего примера, замена будет только в обработчике события «FormShow»
  • Добавим на формы два ЛистБокса, один для отображения списка доступных Менеджеров, другой для Профилей. По клику будем осуществлять подключение.
  • Напишем ещё немного кода
У меня изменения выглядят вот так:



Весь код приложения (проект «Server»):
procedure TForm2.FormShow(Sender: TObject);
begin
  Label1.Text := 'Local Manager: ' + TMServer.Identifier;
  TMServer.DiscoverManagers();
end;

procedure TForm2.ListBox1ItemClick(const Sender: TCustomListBox;
  const Item: TListBoxItem);
begin
  TMServer.PairManager(TMServer.RemoteManagers[Item.Index]);
end;

procedure TForm2.ListBox2ItemClick(const Sender: TCustomListBox;
  const Item: TListBoxItem);
begin
  TAPServer.Connect(TMServer.RemoteProfiles[Item.Index]);
end;

procedure TForm2.TMServerEndManagersDiscovery(const Sender: TObject;
  const ARemoteManagers: TTetheringManagerInfoList);
var
  i: Integer;
begin
  if ARemoteManagers.Count > 0 then
  begin
    for i := 0 to ARemoteManagers.Count - 1 do
    begin
      ListBox1.Items.Add(ARemoteManagers.Items[i].ManagerText);
    end;
  end;
end;

procedure TForm2.TMServerEndProfilesDiscovery(const Sender: TObject;
  const ARemoteProfiles: TTetheringProfileInfoList);
var
  i: Integer;
begin
  if ARemoteProfiles.Count > 0 then
  begin
    for i := 0 to ARemoteProfiles.Count - 1 do
    begin
      ListBox2.Items.Add(ARemoteProfiles.Items[i].ProfileText);
    end;
  end;
end;

procedure TForm2.TMServerPairedFromLocal(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  Memo1.Lines.Add('PairedFromLocal: ' +
      AManagerInfo.ManagerIdentifier + ' ' +
      AManagerInfo.ManagerText);
end;

procedure TForm2.TMServerPairedToRemote(const Sender: TObject;
  const AManagerInfo: TTetheringManagerInfo);
begin
  Memo1.Lines.Add('PairedToRemote: ' +
      AManagerInfo.ManagerIdentifier + ' ' +
      AManagerInfo.ManagerText);
end;

procedure TForm2.TMServerRequestManagerPassword(const Sender: TObject;
  const ARemoteIdentifier: string; var Password: string);
begin
  Password := '12345';
end;
Как видите, весь код соответствует описанным выше трём шагам. Думаю пояснять код ещё раз нет необходимости, но если появились вопросы, то пишите в комменты.

Запускаем оба приложения и видим результат (после клика по найденному менеджеру):


Исходники примера: Скачать с Google Drive

На данный момент, вы узнали о свойствах, методах и событиях у компонентов:

TTetheringManager
  • Свойства: AllowedAdapters, Enabled, Password, Name, Text, Identifier, RemoteProfiles
  • Методы: AutoConnect, DiscoverManagers, PairManager
  • События: OnPairedFromLocal, OnPairedToRemote, OnRequestManagerPassword, OnEndManagersDiscovery, OnEndProfilesDiscovery
TTetheringAppProfile
  • Свойства: Enabled, Group, Manager, Name, Text
  • Методы: Connect
  • События: -
Теперь вы умеете использовать оба режима подключения. В следующей статье мы научимся выполнять удалённые действия.

3 комментария:

  1. Что делать если autoconnect и discoverymanagers не находят ничего. Обращение по ip адресу, работает както не понятно, то находят то ничего не находят.

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

      Удалить