ScriptGate

#ScriptGate
Delphi と JavaScript 間でメソッドの相互呼び出しを実現する ScriptGate をリリースしました。
https://bitbucket.org/freeonterminate/scriptgate

Windows / macOS / iOS / Android に対応しています。

##どんな事ができるのか？
例えば次の JavaScript メソッドを Delphi からコールできます。

```html
<head>
  <script type="text/javascript">
    function helloJS()
    {
      alert("Hello, JavaScript!");
    }
  </script>
</head>
```

```Delphi
procedure TForm1.Button1Click(Sender: TObject);
begin
  FScriptGate.CallScript('helloJS()');
end;
```

逆に Delphi のメソッドを JavaScript からコールできます。

```Delphi
procedure TForm1.HelloDelphi()
begin
  ShowMessage('Hello, Delphi!');
end;
```

```html
<body>
  <a href="delphi:HelloDelphi()">Call Delphi</a>
</body>
```

ここで "delphi:" は TScriptGate のコンストラクタで指定するスキームです（詳しくは後述）。

#ScriptGate を使ってみる


##準備
まずは BitBucket からコードをダウンロードします。

次に新規作成で「マルチデバイスアプリケーション」で「空のアプリケーション」を選びます。
※もちろん、既存のプロジェクトに組み込むことも可能ですが、FireMonkey アプリケーションに限ります。

ダウンロードしたソースを検索パスに追加します。

![sc1.png](https://qiita-image-store.s3.amazonaws.com/0/12977/0fdce35d-ac0f-78b4-c126-8c6937bbd41d.png)

そして、Android も開発ターゲットに含む場合は、SGWebClient.jar を Android のライブラリに追加します。

![sc2.png](https://qiita-image-store.s3.amazonaws.com/0/12977/49c64cf1-33b0-6efb-e206-09ae065e68af.png)

これで準備は完了です。

##TScriptGate の生成

ここでは ScriptGate と WebBrowser1, TForm1 を結びつける方法で使ってみます。

```Delphi

unit Unit1;

interface

uses
  {略}
  SG.ScriptGate; // 追加する

type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
    Layout1: TLayout;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private var
    FScriptGate: TScriptGate; // 追加する
  public
    procedure HelloDelphi; // 追加する
  end;
```

設計時の画面はこんな感じです。

![sc3.png](https://qiita-image-store.s3.amazonaws.com/0/12977/8247149c-4f95-88f2-bbe8-67727ae19dbe.png)

実現部では、まず TScriptGate を生成します。

```delphi
implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  FScriptGate := TScriptGate.Create(Self, WebBrowser1, 'delphi');
end;
```

ここで、TScriptGate のコンストラクタは

```Delphi
constructor Create(
  const iReceiver: TObject;
  const iWebBrowser: TWebBrowser;
  const iScheme: String); reintroduce;
```

と宣言されています。
引数の詳細は下記の通りです。

* iReceiver  
iReceiver は JavaScript からの応答を受け取るインスタンスです。  
今回は TForm1 を指定していますが、どんなクラスのインスタンスでもかまいません。  
ここで指定されたインスタンスのメソッドが呼び出し可能になります。  

例えば

```delphi
type
  TReceiver = class
  public
    procedure Foo;
    procedure Bar(const msg: String);
  end;
```

というクラスのインスタンスを指定すると、JavaScript から Foo, Bar メソッドを呼び出せるようになります。
ここで注意して欲しいのは JavaScript に公開するメソッドのアクセスレベルは public 以上が必要な事です。
メソッド公開に RTTI を利用しているためです。

* iWebBrowser
TScriptGate が結びつく TWebBrowser のインスタンスを指定します。
指定した WebBrowser が読み込んでいる JavaScript のメソッドを呼び出せます。
　

* iScheme
ScriptGate のメソッドを呼び出すスキーム、最初の例で付いていた "delphi:" の事です。
JavaScript を使う時に指定する "JavaScript:" やローカルファイルを指定するときの "file:" と同様の意味です。
ここは何を指定してもかまいませんが、同じ文字列を JavaScript 側でも指定しなくてはなりません。
なお、引数に渡す文字列に ":" は要りません。

そして、JavaScript を呼び出すメソッドと、JavaScript から呼び出されるメソッドを書きます。

```delphi
// JavaScript の helloJS() を呼び出します。
// 無名関数を使って戻値も取得できます。
procedure TForm1.Button1Click(Sender: TObject);
begin
  FScriptGate.CallScript(
    'helloJS()',
    procedure(const iResult: String)
    begin
      ShowMessage(iResult);
    end
  );
end;

// JavaScript に公開されるメソッドで、JavaScript から呼び出されます。
procedure TForm1.HelloDelphi;
begin
  ShowMessage('Hello, Delphi!');
end;
```


WebBrowser1 に読み込ませる HTML は下記の様にします。

```html
<html> 
  <header> 
    <script type="text/JavaScript"> 
      function helloJS() { alert("Hello, JavaScript!"); return "Hello !!"; }
    </script> 
  </head> 

  <body> 
    <br><br> 
    <a href="delphi:HelloDelphi()">Call Delphi procedure</a> 
  <body> 
</html>;
```
この状態で起動すると…

![sg1.png](https://qiita-image-store.s3.amazonaws.com/0/12977/79fbb07a-64ad-673e-667f-3369a9924911.png)

こうなります。

それでは JavaScript から Delphi を呼んでみます。
すると


![sg2.png](https://qiita-image-store.s3.amazonaws.com/0/12977/3aa99e2a-1c50-03d6-5106-e6701b8ec196.png)
こうなります。

次に Delphi から JavaScript を呼んでみると

![a.png](https://qiita-image-store.s3.amazonaws.com/0/12977/e4ab8bca-392c-6603-e0bd-6301fb98cd03.png)

こうなります。
この後、さらに戻値で受け取った文字列を表示します。

相互に呼び出せる事が確認出来ました。

#まとめ
ScriptGate は Windows / macOS / iOS / Android に対応しています。
ここでは簡単のため Win32 で試していますが、同じコードで上記の 4 OS に対応するので、非常に簡単にハイブリッドアプリを作成できます。
是非使ってみてください。