델파이는 성능좋은 네이티브 모바일 앱을 개발할 수 있는 개발 도구입니다.

모든 기능을 네이티브로 개발할 수 있지만, 이미 반응형 웹페이지를 갖고 있는 경우 일부 기능을 웹브라우를 통해 구현해 하이브리드 형태로 개발 할 수 있습니다.

 

이 경우 델파이 코드에서 웹페이지의 자바스크립트를 호출하는 방법은 웹브라우저에서 제공하는 메소드(EvaluateJavaScript)를 사용할 수 있지만, 반대로 웹브라우저에서 델파이 코드를 호출하는 방법은 잘 모르실 것 같아 샘플을 만들어 공개합니다.

 

이글에서는 다음 기능을 소개합니다.

  • 델파이 코드로 웹브라우저의 자바스크립트 코드 호출하기
  • 웹브라우저에서 델파이 메소드 호출하기(파라메터 포함)

 

 

 

 

기본 구성

 

❑ 웹페이지 구성

 

 

웹페이지(http://hjf.pe.kr/fmx/hybrid.php)의 자바스크립트 코드는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script language="JavaScript">
// 델파이에서 호출하는 자바스크립트 메소드
function callJSMethodFromDelphi(){
    alert("[JS] Call from delphi");
}
 
// 델파이 메소드를 호출하는 자바스크립트 함수 2종
function callDelphiMethodFromJS(){
    window.location = "jscall://callDelphiMethodFromJS";
}
 
function callDelphiMethodFromJSWithParam(){
    window.location = "jscall://callDelphiMethodFromJSWithParam?Hello|1234";
}
</script>

웹페이지에서 델파이 코드 호출은 아래와 같이 2개의 버튼으로 처리합니다..

1
2
<input type="button" value="Call delphi method" onclick="callDelphiMethodFromJS();"><br>
<input type="button" value="Call delphi method(with parameters)" onclick="callDelphiMethodFromJSWithParam();">

 

❑ 델파이 앱 화면 구성

 

델파이에서 자바스크립트 호출하기

 

델파이에서 웹브라우저 안의 자바스크립트 호출은 EvaluateJavaScript 메소드를 이용합니다. 자바스크립트 함수 뿐 아니라 여러줄의 구문도 실행할 수 있습니다.

 

델파이 코드

 

델파이에서 자바스크립트의 callJSMethodFromDelphi 함수 실행

1
2
3
4
procedure TForm1.Button1Click(Sender: TObject);
begin
  WebBrowser1.EvaluateJavaScript('callJSMethodFromDelphi();');
end;

 

웹페이지의 자바스크립트 코드

 

자바스크립트는 다음과 같이 메시지 다이얼로그를 출력하도록 되어있습니다.

 

1
2
3
function callJSMethodFromDelphi(){
    alert("[JS] Call from delphi");
}

 

테스트 결과

 

 

EvaluateJavaScript 메소드 자세히 보기(웹브라우저 html 코드를 적용할 수 있는 LoadFromStrings 메소드도 활용도가 높습니다.)

 

웹페이지에서 델파이 메소드 호출하기

웹페이지에서 델파이 메소드를 호출하는 원리는 아래와 같습니다.

  1. 델파이는 웹브라우저 주소가 변경되면 이벤트를 받을 수 있다.
  2. 웹페이지에서 웹브라우저 주소를 변경할 수 있다.
  3. 웹페이지에서 주소를 http:// 형태의 페이지 주소가 아닌, 델파이 메소드를 호출하라는 사용자 포맷의 주소를 호출한다.
  4. 델파이에서 주소 변경 이벤트 발생 시 사용자포맷 주소인 경우, 주소를 분석 해 델파이 메소드를 호출한다.

 

❑ 델파이 파이어몽키용 웹브라우저 주소 변경 이벤트 종류

 

웹브라우저(TWebBrowser)의 주소변경 이벤트는 다음과 같습니다.

 

이벤트

 발생 조건

 OnDidFailLoadWithError

  페이지 로드 중 에러가 난 경우 발생

 OnDidFinishLoad

  페이지 로드가 완료한 경우 발생
 OnDisStartLoad   페이지 로드를 시작할때 발생
 OnShouldStartLoadWithRequest

 

  요청에 의해 페이지 로드를 시작할때 발생

 

 

이 데모에서는 페이지 로드 요청 시 발생하는 OnShouldStartLoadWithRequest 이벤트를 이용합니다.

(메소드 호출과정에 페이지가 로드되지 않기 때문에 OnDisStartLoad 이벤트는 발생하지 않습니다.)

 

 

❑ 웹페이지에서 델파이 메소드 호출하기

 

웹페이지에서 델파이 메소드 호출은 아래 자바스크립트를 호출해 동작합니다.

 

1
2
3
4
5
6
7
function callDelphiMethodFromJS(){
    window.location = "jscall://callDelphiMethodFromJS";
}
 
function callDelphiMethodFromJSWithParam(){
    window.location = "jscall://callDelphiMethodFromJSWithParam?Hello|1234";
}

 

 

위 자바스크립트 코드는 웹페이지 주소(window.location)를 변경하는 코드로, 사용자 포맷(jscall://)으로 주소를 변경합니다.

 

제가 정의한 포맷은 다음과 같습니다.(임의로 정한 규칙임으로 원하는 방식으로 정의해서 사용하기 바랍니다.)

 

 포맷 정의

용도 

 jscall:// 

 델파이 코드를 호출하는 주소라는 의미

 callDelphiMethodFromJSWithParam

 호출할 델파이 코드명

 ?Hello|1234

 "?" 뒤에는 파라메터를 추가합니다. 파라메터는 파이프("|")로 구분합니다.

 

 

다음으로 웹페이지에서 위 포맷으로 주소 변경 시, 델파이에서 감지해 메소드를 호출하도록 구현합니다.

 

❑ 델파이에서 사용자 포맷 주소 감지하고 분석하기

 

델파이 웹브라우저 OnShouldStartLoadWithRequest 이벤트에는 아래와 같이 구현했습니다.

 

1
2
3
4
5
6
7
8
9
10
11
procedure TForm1.WebBrowser1ShouldStartLoadWithRequest(ASender: TObject;
  const URL: string);
var
  MethodName: string;
  Params: TArray<tvalue>;
begin
  if ProcessMethodUrlParse(URL, MethodName, Params) then
  begin
    CallMethod(MethodName, Params);
  end;
end;</tvalue>

 

 

ProcessmethodUrlParse 메소드로 URL을 분석하고, 메소드 URL인 경우 메소드를 호출하는 CallMethod를 호출합니다.

 

메소드 URL 분석

 

 

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
28
29
30
31
32
33
34
35
36
37
38
// URL format
//  jscall://{method name}?{Param1}|{ParamN}
function TForm1.ProcessMethodUrlParse(AUrl: string;
  var MethodName: string; var Parameters: TArray<TValue>): Boolean;
const
  JSCALL_PREFIX = 'jscall://';
  JSCALL_PREFIX_LEN = Length(JSCALL_PREFIX);
var
  I: Integer;
  ParamStr: string;
  ParamArray: TArray<string>;
begin
  Result := False;
 
  // iOS에서 특수기호(|)가 멀티바이트로 넘어옴
  AUrl := TNetEncoding.URL.Decode(AUrl);
 
  if AUrl.IndexOf(JSCALL_PREFIX) = -1 then
    Exit(False);
 
  if AUrl.IndexOf('?') > 0 then
  begin
    MethodName := AUrl.Substring(JSCALL_PREFIX_LEN, AUrl.IndexOf('?')-JSCALL_PREFIX_LEN);
 
    ParamStr := AUrl.Substring(AUrl.IndexOf('?')+1, Length(AUrl));
    ParamArray := ParamStr.Split(['|']);
    SetLength(Parameters, length(ParamArray));
    for I := 0 to Length(ParamArray)-1 do
      Parameters[I] := ParamArray[I];
  end
  else
    MethodName := AUrl.Substring(JSCALL_PREFIX_LEN, MaxInt);
  if MethodName.IndexOf('/') > 0 then
    MethodName := MethodName.Replace('/', '');
 
  Result := not MethodName.IsEmpty;
end;</string>

 

❑ 분석한 메소드 호출

 

웹페이지에서 호출할 델파이 메소드는 아래와 같이 자바스크립트와 동일한 이름으로 작성했습니다.

 

1
2
3
4
5
6
7
8
9
procedure TForm1.callDelphiMethodFromJS;
begin
  ShowMessage('[DELPHI] Call from JS');
end;
 
procedure TForm1.callDelphiMethodFromJSWithParam(AStr1, AStr2: string);
begin
  ShowMessage(Format('[DELPHI] Call from JS(%s, %s)', [AStr1, AStr2]));
end;

 

텍스트 타입의 메소드이름으로 메소드를 호출하는 방법은 간단하게 조건문으로 호출하는 방법도 있고, RTTI를 이용해 메소드이름으로 메소드를 찾아 호출하는 방법으로도 구현할 수 있습니다.

 

조건문으로 메소드 호출

 

 

1
2
3
4
5
6
7
function TForm1.CallMethod(AMethodName: string; AParameters: TArray<TValue>): TValue;
begin
  if AMethodName = 'callDelphiMethodFromJS' then
    callDelphiMethodFromJS
  else if AMethodName = 'callDelphiMethodFromJSWithParam' then
    callDelphiMethodFromJSWithParam(AParameters[0].AsString, AParameters[1].AsString);
end;

 

 

 

RTTI를 이용해 메소드 호출

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function TForm1.CallMethod(AMethodName: string; AParameters: TArray<TValue>): TValue;
var
  RttiCtx: TRttiContext;
  RttiTyp: TRttiType;
  RttiMtd: TRttiMethod;
begin
  RttiCtx := TRttiContext.Create;
  RttiTyp := RttiCtx.GetType(Self.ClassInfo);
  if Assigned(RttiTyp) then
  begin
    RttiMtd := RttiTyp.GetMethod(AMethodName);
    if Assigned(RttiMtd) then
      Result := RttiMtd.Invoke(Self, AParameters);
  end;
  RttiMtd.Free;
  RttiTyp.Free;
  RttiCtx.Free;
end;

 

테스트 결과

 

<주의>

 

 

 

안드로이드 앱의 웹브라우저에서 델파이 코드 호출 시 ERR_UNKNOWN_URL_SCHEME 오류가 발생하는 경우 다음 글을 참고해 조치하기 바랍니다.

 

 - http://blog.hjf.pe.kr/378

 

 

샘플 다운로드

다운로드 : 

 HybridAppDemoSrc.zip

 
번호 제목 글쓴이 날짜 조회 수
공지 [DelphiCon 요약] 코드사이트 로깅 실전 활용 기법 (Real-world CodeSite Logging Techniques) 관리자 2021.01.19 15465
공지 [UX Summit 요약] 오른쪽 클릭은 옳다 (Right Click is Right) 관리자 2020.11.16 13970
공지 [10.4 시드니] What's NEW! 신기능 자세히 보기 관리자 2020.05.27 16505
공지 RAD스튜디오(델파이,C++빌더) - 고객 사례 목록 관리자 2018.10.23 22061
공지 [데브기어 컨설팅] 모바일 앱 & 업그레이드 마이그레이션 [1] 관리자 2017.02.06 23271
공지 [전체 목록] 이 달의 기술자료 & 기술레터 관리자 2017.02.06 18932
공지 RAD스튜디오(델파이, C++빌더) - 시작하기 [1] 관리자 2015.06.30 39265
공지 RAD스튜디오(델파이,C++빌더) - 모바일 앱 개발 사례 (2020년 11월 업데이트 됨) 험프리 2014.01.16 174728
54 TListView 행별로 배경색 설정 및 글꼴변경하기 험프리 2017.09.08 1684
53 [REST API][실습] 데이터셋 기반 REST API 개발하기 험프리 2017.06.13 2178
52 [REST API][실습] REST API 클라이언트 개발하기(REST Client 이용) [2] 험프리 2017.05.23 7102
51 [REST API][실습] REST API 서버 개발하기(엔드포인트 구현, RAD 서버 이용) [5] 험프리 2017.05.23 4526
50 이 달의 기술자료 - 2017년 02월 file 험프리 2017.01.31 699
49 델파이에서 사용하는 각 Stream(스트림) 정리 김원경 2017.01.04 6165
48 [RAD서버] [웨비나-딥다이브] 매장 관리 솔루션 개발하기(개발 시나리오와 데모) file 험프리 2016.11.02 1321
47 [동영상] 앱테더링 데이터 암호화/복호화 방법 file 험프리 2016.11.01 804
46 이 달의 기술자료 - 2016년 06월 file 험프리 2016.05.27 632
45 [베를린] TBufferedFileStream을 이용해 TFileStream 보다 더 빠르게 파일을 읽고, 쓸수 있습니다. file 험프리 2016.05.09 3087
44 인터베이스 데이터베이스와 테이블 생성하기 [3] file 험프리 2016.01.07 2501
43 [따라하기] 건강데이터 수집 및 기록 시스템 #1 - BLE 기반 스마트 체중계에서 실시간 데이터 받기 [1] Humphery 2015.10.02 5798
42 XE7과 XE8에서 iOS 9용 iOS 32비트 애플리케이션을 빌드하는 절차안내. Humphery 2015.09.25 474
41 [따라하기] 위험지역 경보 시스템 #1 - 위험지역 진입 경보앱 만들기 [1] Humphery 2015.07.30 3743
» [하이브리드 앱 개발] 웹페이지에서 델파이 함수 호출하기 Humphery 2015.06.26 4076
39 안드로이드 웹브라우저에서 "tel:, sms:" 링크가 동작하지 않는 이슈 해결하기 Humphery 2015.06.26 4837
38 [XE8] 번거로운 수작업을 줄여 핵심기능 개발에 집중할 수 있는 개발 생산성 향상도구 Humphery 2015.04.28 897
37 [XE8] 근거리 위치기반 서비스를 개발할 수 있는 비콘(Beacon) 연동하기 [1] Humphery 2015.04.15 3942
36 모바일 앱 라이프사이클 이벤트 처리하기 Humphery 2015.04.09 1566
35 모바일 앱 라이프 사이클 이벤트 처리하기(앱 완전 구동 후 실행하기) [1] Humphery 2015.04.09 944