앱테더링(App Tethering)?

앱 테더링은 2개의 개별적인 앱을 서로 연결(테더링)해서 데이터를 주고 받을 수 있는 기술입니다.

앱테더링 기술을 이용해 VCL어플리케이션에서 모바일로 데이터를 제공하면 모바일에서 뷰어만 빠르게 만들어 아주 빠르고 쉽게 모바일앱을 개발할 수 있습니다.

(모바일 앱의 동작을 다시 VCL 앱으로 전송해 사용자의 액션과 모바일 이미지등을 VCL 앱에서 사용하면 더 강력한 시스템으로 탈바꿈할 수 있습니다.)

❑ 앱테더링 컴포넌트

앱 테더링은 TTetheringManager, TTetheringAppProfile 두개의 컴포넌트를 통해 구현할 수 있습니다. 이번글에서는 각 컴포넌트의 자세한 속성과 이벤트에 대해서는 다루지 않습니다. 하지만 아래의 "앱테더링 데모를 통해 기능 살펴보기" 단계를 보시면 주요한 대부분의 속성과 이벤트를 다루고 있기 때문에 충분히 기능을 익힐 수 있습니다.

더 자세히 알고 싶은 기능(속성, 이벤트)는 엠바카데로 기술 도움말(영문)을 통해서 익혀보시기 바랍니다.

아래는 앱테더링 기술이 제공하는 대표적인 속성입니다.

앱테더링의 대표 기능

  • 동일한 서브넷에서 동반자앱 자동탐색 기능(P2P기반으로 별도의 서버 구성이 필요하지 않습니다.)
  • 지정한 IP / 지정한 서브넷(192.168.1.0: 192.168.1.1 ~ 192.168.1.255)에서 탐색 시도
  • 블루투스 기반 앱테더링
  • String / Stream 기반 데이터 전송 기능 제공(Stream이므로 사실상 모든 데이터 전송 가능)
  • 동반자앱에 공개된 Action(명령)을 원격에서 호출하는 Remote Action 기능제공
  • VCL / FMX 2개의 프레임워크 지원
    • VCL 앱을 모바일과 연결해 쉽게 모바일로 전환/확장 할 수 있는 가능성 제공
    • 모바일에서 센서를 연결하면 VCL앱을 IoT로 바로 확장 가능
아래 데모영상을 통해 여러분들의 가능성을 만들어 보시기 바랍니다.

앱테더링 데모를 통해 기능 살펴보기

아래 데모영상은 VCL 어플리케이션을 모바일 앱으로 확장하기 위해 앱테더링 기술의 가장 기본적인 부분을 설명합니다. 

데모영상을 보시고 기능을 익히신 후 앱테더링 기능을 여러분의 프로젝트에 도입하면 어떤 기능을 확장할 수 있을지 생각해 보시고 여러분의 제품에 적용해보시기 바랍니다.

  • 탐색과 접속
    • 1단계, 동일 서브넷에서 접속대상 탐색시도
    • 2단계, 탐색된 테더링 매니저 표시
    • 3단계, 선택 매니저와 연결(페어링)
    • 4단계, 탐색된 테더링 프로필 표시
    • 5단계, 선택 페어링과 연결(페어링)
  • 데이터 송수신
    • 6단계, 문자열 데이터 전송
    • 7단계, 데이터 수신하기(문자열, 스트림)
    • 8단계, 이미지(스트림) 데이터 전송
    • 9단계, 원격지에 정의된 액션(명령) 호출

1, 동일 서브넷에서 접속대상 탐색시도하기

테더링매니저의 DiscoverManagers 메소드를 통해 주변(동일 서브넷)의 동반자 앱을 탐색합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure TForm2.btnDiscoverManagerClick(Sender: TObject);
begin
  InitControls;
 
  LogAndInfo('동일 서브넷에서 접속대상을 찾습니다.');
  // (#1) 주변에서 TetheringManager 발견명령
  TetheringManager.DiscoverManagers;
 
  // (#2) TetheringAppProfile의 Group 기반으로 자동 연결
//  TetheringManager.AutoConnect(3000);
 
  //  (#3) 대상을 지정해 접속할 수 있습니다.
//  TetheringManager.DiscoverManagers(3000, 127.0.0.1);
end;

AutoConnect(#2, TetheringAppProfile의 Group이 동일한 대상으로 자동 접속), 접속 대상을 지정(#3)등 다양한 접속 방식을 제공합니다.

2, 발견된 테더링 매니저 정보표시

탐색(DiscoverManagers)이 완료되면 TetheringManager의 OnEndManagersDiscovery 이벤트가 발생하고, ARemoteManagers 파라메터를 통해 탐색된 매니저정보를 제공합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
procedure TForm2.TetheringManagerEndManagersDiscovery(const Sender: TObject;
  const ARemoteManagers: TTetheringManagerInfoList);
var
  Info: TTetheringManagerInfo;
begin
  cbxRemoteManagers.Items.Clear;
  for Info in ARemoteManagers do
  begin
    Log(Format('[검색된 매니저]'#13#10#9'%s'#13#10#9'%s'#13#10#9'%s'#13#10#9'%s', [
      Info.ManagerIdentifier,
      Info.ManagerName,
      Info.ManagerText,
      Info.ConnectionString
    ]));
    cbxRemoteManagers.Items.Add(Format('%s(%s)', [Info.ManagerText, Info.ConnectionString]));
  end;
  if cbxRemoteManagers.Items.Count > 0 then
  begin
    cbxRemoteManagers.ItemIndex := 0;
    btnPairManager.Enabled := True;
  end;
  LogAndInfo(Format('접속 대상이 [%d]건 발견되었습니다.', [ARemoteManagers.Count]));
end;

3, 선택한 매니저와 연결(페어링)

접속할 대상 매니저를 선택 후 페어링(PairManager)을 시도합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 선택한 매니저와 연결
procedure TForm2.btnPairManagerClick(Sender: TObject);
var
  N: Integer;
begin
  if cbxRemoteManagers.ItemIndex < 0 then
    Exit;
 
  N := cbxRemoteManagers.ItemIndex;
  LogAndInfo(TetheringManager.RemoteManagers[N].ManagerText + ' - 매니저와 페어링 시도');
  TetheringManager.PairManager(TetheringManager.RemoteManagers[N]);
end;
 
// 매니저 비밀번호 설정
procedure TForm2.TetheringManagerRequestManagerPassword(const Sender: TObject;
  const ARemoteIdentifier: string; var Password: string);
begin
  Password := edtPassword.Text;
 
  TThread.Synchronize(TThread.CurrentThread,
    procedure begin
      LogAndInfo('[비밀번호 요청] - ' + edtPassword.Text);
    end);
end;

매니저간 페어링 시도 시 서로의 비밀번호를 통해 연결을 허용합니다. 만약 매니저간의 비밀번호가 맞지 않다면, TetheringManager 컴포넌트에서 인증오류(OnAuthErrorFromLocal, OnAuthErrorFromRemote) 이벤트가 발생하고 페어링은 실패합니다.

비밀번호는 TetheringManager.Password 속성을 통해서도 설정할 수 있습니다.

4, 발견된 테더링 프로필 정보표시

매니저간 연결(페어링)되면 TetheringManager의 OnEndProfilesDiscovery 이벤트가 발생되며 ARemoteprofiles 파라메터를 통해 탐색된 프로필 정보를 제공합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 프로필 발견완료 이벤트
procedure TForm2.TetheringManagerEndProfilesDiscovery(const Sender: TObject;
  const ARemoteProfiles: TTetheringProfileInfoList);
var
  Info: TTetheringProfileInfo;
begin
//  Log('TetheringManagerEndProfilesDiscovery');
  cbxRemoteProfiles.Items.Clear;
  for Info in ARemoteProfiles do
  begin
    Log(Format('[앱 프로필]'#13#10#9'%s'#13#10#9'%s'#13#10#9'%s'#13#10#9'%s'#13#10#9'%s', [
      Info.ManagerIdentifier,
      Info.ProfileIdentifier,
      info.ProfileText,
      Info.ProfileGroup,
      Info.ProfileType
 
    ]));
    cbxRemoteProfiles.Items.Add(Format('%s(%s)', [Info.ProfileText, Info.ProfileType]));
  end;
  if cbxRemoteProfiles.Items.Count > 0 then
  begin
    cbxRemoteProfiles.ItemIndex := 0;
    btnPairProfile.Enabled := True;
  end;
  LogAndInfo(Format('대상 프로필 [%d]건 발견되었습니다.', [ARemoteProfiles.Count]));
end;

5, 선택한 프로필과 연결

접속할 대상 프로필을 선택(TetheringAppProfile.Connect)하여 페어링 시도합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 선택한 프로필과 연결
procedure TForm2.btnPairProfileClick(Sender: TObject);
var
  N: Integer;
begin
  if cbxRemoteProfiles.ItemIndex < 0 then
    Exit;
 
  N := cbxRemoteProfiles.ItemIndex;
  LogAndInfo(TetheringManager.RemoteProfiles[N].ProfileText + ' - 프로필과 페어링 시도');
  if TetheringAppProfile.Connect(TetheringManager.RemoteProfiles[N]) then
  begin
    LogAndInfo('페어링 성공!!');
    InitControls;
  end;
end;

페어링이 완료되면 데이터 전송, 데이터 수신, 원격 액션 호출등의 작업이 가능해 집니다.

6, 문자열 전달

TetheringAppProfile.SendString 메소드를 통해 명령어, 데이터등의 문자열 데이터를 전달할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
procedure TForm2.btnSendStrHelloClick(Sender: TObject);
begin
  LogAndInfo('문자열 전달 - 동반자 모바일앱에 Hello 전달');
  TetheringAppProfile.SendString(
    TetheringAppProfile.ConnectedProfiles.First,
    'HELLO',
    '안녕? App Tethering!!!');
end;
 
procedure TForm2.btnSendStrRSClick(Sender: TObject);
begin
  LogAndInfo('문자열 전달 - 동반자 모바일앱에 ReverseString 전달');
  TetheringAppProfile.SendString(
    TetheringAppProfile.ConnectedProfiles.First,
    'ReverseString',
    '반갑습니다.');
end;

SendString 메소드는 3개의 파라메터를 전달합니다.

  1. 전송할 앱 프로필 객체
  2. 수신 시 리소스의 힌트로 받을 수 있는 설명(Description)
  3. 문자열 데이터 값
ReverseString 문자열 데이터는 상대방(모바일 앱)에서 수신 시 글자를 뒤집어(반갑습니다. > .다니습갑반) 다시 전송하도록 구현되었습니다.

7, 데이터 수신

상대방 동반자앱에서 데이터를 보내면 TetheringAppProfile의 OnResourceReceived 이벤트를 통해 데이터를 수신할 수 있습니다. 문자열 데이터, 이미지 데이터(Stream)등이 모두 OnResourceReceived 이벤트를 통해 수신합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<p>procedure TForm2.TetheringAppProfileResourceReceived(const Sender: TObject;
  const AResource: TRemoteResource);
begin
  case AResource.ResType of
  // 데이터(SendString)
  TRemoteResourceType.Data:
    begin
      // ReverseString을 받은 모바일에서 전송한 응답
      if AResource.Hint = 'EchoString' then
        LogAndInfo('EchoString : ' + AResource.Value.AsString)
    end;
  // 스트림(SendStream)
  TRemoteResourceType.Stream:
    begin
      // 모바일에서 전송한 이미지
      if AResource.Hint = 'FMXIMG' then
      begin
        LogAndInfo('이미지 수신');
        LoadImage(AResource.Value.AsStream);
      end;
    end;
  end;
end;</p>

AResource 파라메터 주요 속성

  • AResource.ResType
    • SendString으로 전송 시 TRemoteResourceType.Data로 SendStream으로 전송 시 TRemoteResourceType.Stream으로 수신
  • AResource.Hint
    • SendString과 SendStream의 Description 파라메터에 입력한 값을 담고 있습니다.
  • AResource.Value
    • SendString과 SendStream의 Value(AString, AStream)에 입력한 값을 담고 있습니다.

8, 데이터 전달 - 이미지전송

이미지, 파일 등의 데이터를 TStream으로 변환해 동반자 앱으로 전달 할 수있습니다.(TStream은 TMemoryStream, TFileStream, TStringStream 등의 부모클래스이므로  다양한 데이터를 전달할 수 있습니다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
procedure TForm2.btnSendStreamImageClick(Sender: TObject);
var
  Stream: TMemoryStream;
begin
  LogAndInfo('데이터 전달 - 이미지 데이터를 TStream으로 동반자 모바일앱에 전달');
  Stream := TMemoryStream.Create;
  try
    Image1.Picture.Graphic.SaveToStream(Stream);
      TetheringAppProfile.SendStream(TetheringManager.RemoteProfiles.First,
      'VCLIMG',
      Stream
    );
  finally
    Stream.Free;
  end;
  PageControl1.TabIndex := 2;
//  TetheringAppProfile.SendStream()
end;

9, 원격지의 명령 호출(이미지 전송 요청) 

TetheringAppProfile.RunRemoteAction 메소드를 통해 원격지에 공개된 Action을 실행 할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
// 원격지의 액션 호출
procedure TForm2.btnRunRemoteActionClick(Sender: TObject);
begin
  LogAndInfo('원격 명령 호출 - 원격지(동방자 모바일 앱)의 ActionSendImg 액션 호출');
  TetheringAppProfile.RunRemoteAction(
    TetheringManager.RemoteProfiles.First,
    'ActionSendImg'
  );
  PageControl1.TabIndex := 3;
end;

모바일 앱의 TetheringAppProfile에는 Actions 속성에 아래와 같이 Action이 등록되어 있습니다.

TetheringAppProfile의 Actions에 등록된 Action(명령)은 외부로 공개(IsPublic)할 수 있어 외부에서 RunRemoteAction 메소드를 통해 호출할 수 있습니다.

❑ 위 데모 소스코드 받기

앱테더링 데모 더 살펴보기...

RAD Studio XE7의 샘플 프로젝트에는 아래의 다양한 앱테더링 데모가 있습니다.

  • 앱테더링 샘플 프로젝트 경로

    • C:\Users\Public\Documents\Embarcadero\Studio\15.0\Samples\Object Pascal\RTL\Tethering

❑ BDShoppingList

  • 앱테더링 기술을 이용해 데스크탑의 쇼핑 데이터를 모바일에 제공합니다.

  • 모바일 화면에서 쇼핑항목의 구매를 선택하면 구매명령을 데스크탑으로 전달해 구매처리를 완료합니다.

  • 데스크탑과 모바일은 변경된 데이터를 수시로 동기화합니다.

  • http://docwiki.embarcadero.com/CodeExamples/XE7/en/RTL.BDShoppingList_Sample

❑ DesktopCast

❑ MediaPlayer

❑ PhotoWall

참고 글

번호 제목 글쓴이 날짜 조회 수
공지 [DelphiCon 요약] 코드사이트 로깅 실전 활용 기법 (Real-world CodeSite Logging Techniques) 관리자 2021.01.19 14390
공지 [UX Summit 요약] 오른쪽 클릭은 옳다 (Right Click is Right) 관리자 2020.11.16 13023
공지 [10.4 시드니] What's NEW! 신기능 자세히 보기 관리자 2020.05.27 15532
공지 RAD스튜디오(델파이,C++빌더) - 고객 사례 목록 관리자 2018.10.23 21065
공지 [데브기어 컨설팅] 모바일 앱 & 업그레이드 마이그레이션 [1] 관리자 2017.02.06 22297
공지 [전체 목록] 이 달의 기술자료 & 기술레터 관리자 2017.02.06 17933
공지 RAD스튜디오(델파이, C++빌더) - 시작하기 [1] 관리자 2015.06.30 38228
공지 RAD스튜디오(델파이,C++빌더) - 모바일 앱 개발 사례 (2020년 11월 업데이트 됨) 험프리 2014.01.16 173741
423 [업데이트] RAD Studio XE7 Update 1 개선된 내용 Humphery 2014.11.27 2041
422 이 달의 기술자료 - 2014년 12월 file 험프리 2014.11.26 32446
421 RAD Studio XE7에서 iOS개선된 내용 관리자 2014.11.22 1139
420 RAD Studio XE7에서 안드로이드 개선된 내용 [1] 관리자 2014.11.22 1466
419 RAD Studio XE7에서 VCL개선된 내용 관리자 2014.11.22 1210
418 [세미나 자료] 20141113 RAD Studio XE7 DeepDive file 관리자 2014.11.14 1424
» VCL앱을 모바일앱으로 쉽게 확장할 수 있는 앱테더링 자세히 살펴보기! [3] Humphery 2014.11.11 3356
416 더 쉬운코드, 더 유연한 코드를 작성할 수 있는 현대식 문법 [1] Humphery 2014.11.06 4611
415 RAD Studio XE7에서 추가된 안드로이드 기능 익히기(동영상) Humphery 2014.11.05 2057
414 델파이 문법을 익힐 수 있는 문서모음 [2] Humphery 2014.11.03 2631
413 XE7에서 추가 된 안드로이드 프로젝트에서 외부 라이브러리(jar) 사용을 위한 정보 [1] Humphery 2014.11.03 3220
412 [업데이트][Hotfix] iOS 배포와 요세미티, VCL Bitmap 파일 보안취약점 패치 Humphery 2014.10.22 2038
411 [따라하기] "나의 도서관 앱" 개발 Humphery 2014.10.15 4097
410 [동영상] 8단계로 완성하는 "2014년 출시 앨범" 앱 개발 "15"분 만에 완료하기 관리자 2014.10.14 1848
409 이 달의 기술자료 - 2014년 11월 험프리 2014.10.13 54111
408 RAD Studio 프리미엄 스타일 사용방법(VCL / FMX) [1] Humphery 2014.10.10 5393
407 8단계로 완성하는 "2014년 출시 앨범" 앱 개발 따라하기 [1] file Humphery 2014.10.07 3649
406 [광주 세미나 발표자료] RAD Studio XE7 Direct, LIVE! 관리자 2014.09.30 1307
405 [XE7] 사물인터넷(IoT)와 RAD Studio -블루투스 [2] Humphery 2014.09.24 4082
404 FireDAC 시작하기 Humphery 2014.09.23 2959