Delphi [하이브리드 앱 개발] 웹페이지에서 델파이 함수 호출하기
2015.06.26 23:03
델파이는 성능좋은 네이티브 모바일 앱을 개발할 수 있는 개발 도구입니다.
모든 기능을 네이티브로 개발할 수 있지만, 이미 반응형 웹페이지를 갖고 있는 경우 일부 기능을 웹브라우를 통해 구현해 하이브리드 형태로 개발 할 수 있습니다.
이 경우 델파이 코드에서 웹페이지의 자바스크립트를 호출하는 방법은 웹브라우저에서 제공하는 메소드(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(){ } function callDelphiMethodFromJSWithParam(){ } </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 메소드도 활용도가 높습니다.)
웹페이지에서 델파이 메소드 호출하기
웹페이지에서 델파이 메소드를 호출하는 원리는 아래와 같습니다.
- 델파이는 웹브라우저 주소가 변경되면 이벤트를 받을 수 있다.
- 웹페이지에서 웹브라우저 주소를 변경할 수 있다.
- 웹페이지에서 주소를 http:// 형태의 페이지 주소가 아닌, 델파이 메소드를 호출하라는 사용자 포맷의 주소를 호출한다.
- 델파이에서 주소 변경 이벤트 발생 시 사용자포맷 주소인 경우, 주소를 분석 해 델파이 메소드를 호출한다.
❑ 델파이 파이어몽키용 웹브라우저 주소 변경 이벤트 종류
웹브라우저(TWebBrowser)의 주소변경 이벤트는 다음과 같습니다.
이벤트 |
발생 조건 |
OnDidFailLoadWithError |
페이지 로드 중 에러가 난 경우 발생 |
OnDidFinishLoad |
페이지 로드가 완료한 경우 발생 |
OnDisStartLoad | 페이지 로드를 시작할때 발생 |
OnShouldStartLoadWithRequest
|
요청에 의해 페이지 로드를 시작할때 발생 |
이 데모에서는 페이지 로드 요청 시 발생하는 OnShouldStartLoadWithRequest 이벤트를 이용합니다.
(메소드 호출과정에 페이지가 로드되지 않기 때문에 OnDisStartLoad 이벤트는 발생하지 않습니다.)
❑ 웹페이지에서 델파이 메소드 호출하기
웹페이지에서 델파이 메소드 호출은 아래 자바스크립트를 호출해 동작합니다.
1
2
3
4
5
6
7
|
function callDelphiMethodFromJS(){ } function callDelphiMethodFromJSWithParam(){ } |
위 자바스크립트 코드는 웹페이지 주소(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} // e.g> jscall://callDelphiMethodFromJSWithParam?Hello|1234 function TForm1 . ProcessMethodUrlParse(AUrl: string ; var MethodName: string ; var Parameters: TArray<TValue>): Boolean ; const 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 오류가 발생하는 경우 다음 글을 참고해 조치하기 바랍니다.