пятница, 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
  • События: -
Теперь вы умеете использовать оба режима подключения. В следующей статье мы научимся выполнять удалённые действия.

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