공통 VCL앱을 모바일앱으로 쉽게 확장할 수 있는 앱테더링 자세히 살펴보기!
2014.11.11 18:34
앱테더링(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개의 파라메터를 전달합니다.
- 전송할 앱 프로필 객체
- 수신 시 리소스의 힌트로 받을 수 있는 설명(Description)
- 문자열 데이터 값
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 메소드를 통해 호출할 수 있습니다.
❑ 위 데모 소스코드 받기
https://github.com/hjfactory/FMX.Devgear/tree/master/Demos/AppTetheringBasicDemo
AppTetheringBasicDemo.zip(앱테더링 소스코드)를 다운받으세요.
앱테더링 데모 더 살펴보기...
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
앱테더링 기술을 활용해 데스크탑 화면을 모바일에 방송하는 샘플입니다.
http://docwiki.embarcadero.com/CodeExamples/XE7/en/RTL.DesktopCast_Sample
❑ MediaPlayer
데스크탑에서 동영상을 재생하고 모바일에서는 데스크탑의 동영상을 제어(시작/중지/위치이동/볼륨)합니다.
http://docwiki.embarcadero.com/CodeExamples/XE7/en/RTL.MediaPlayer_Sample
❑ PhotoWall
앱테더링 기술을 활용해 모바일에서 찍은 사진을 데스크탑으로 전송합니다.
http://docwiki.embarcadero.com/CodeExamples/XE7/en/RTL.PhotoWall_Sample
참고 글
댓글 3
-
가라사대
2015.06.26 20:18
-
Humphery
2015.07.03 00:33
1, 앱테더링은 블루투스를 정상 지원합니다.
앱테더링은 네트워크(WiFi)와 블루투스를 모두 지원합니다.
저 또한 질문해 주셔서 다음 샘플로 블루투스 연동 테스트해봤는데 잘됩니다.
C:\Users\Public\Documents\Embarcadero\Studio\16.0\Samples\Object Pascal\Mobile Samples\Device Sensors and Services\App Tethering\MediaPlayer
블루투스 연동 시 살펴보실 부분은
1, 모바일 디바이스(안드로이드)와 머신(윈도우, 맥)이 블루투스 페어링이 되어 있어야 합니다.
2, 모바일 디바이스는 안드로이드만 지원합니다.
3, 모바일 프로젝트에서 블루투스 권한을 설정해야 합니다.(안드로이드만)
앱테더링 기술문서 : http://docwiki.embarcadero.com/RADStudio/XE8/en/Using_App_Tethering
2, 모바일 실행하면 검은 화면만 보입니다.
다음 링크에서 해결방안을 찾아보세요.
http://tech.devgear.co.kr/delphi_qna/411978
-
YGPOS
2017.05.24 01:54
안녕하세요.
이 글을 보고 따라서 만들어보고 있습니다.
멀티디바이스 앱을 윈도우모드로 할 경우 데스크탑 앱과 테더링 연결이 잘 되지만(그림 1, 2)
안드로이드 AVD 또는 실제 스마트폰(Nexus5X)에서 실행할 경우 연결이 되지 않습니다.(그림 3, 4)
혹시 안드로이드용 빌드 할 때 별도로 설정이 필요한 것인지, 아니면 또 다른 해결방법이 있는지 궁금합니다.
감사합니다.
MobileTetheringApp의 경우 TetheringManager1.AllowedAdapter = Bluetooth 로 설정 후 모바일에서 실행하면 검은 화면만 보입니다.
위 값을 Network로 했을 경우에는 정상 작동 합니다.
위 컴포넌트가 BlueTooth를 지원하지 않는 것일까요?