LoginSignup
3
1

More than 3 years have passed since last update.

Lightning Aura ComponentとCTIアダプタ(Visualforce)間での相互通信

Posted at

Lightning Aura ComponentとCTIアダプタ(Visualforce)間での相互通信

Lightning Aura ComponentとCTIアダプタ(Visualforce)でデータのやり取りを行う必要がありました。しかし、直接通信する手段がありません。そのため、JavaScriptのWeb Messaging API「postMessage」を使うことにより間接的にメッセージ通信することにより実現しました。

条件

  • CTIアダプタにはVisualforceが設定されている
  • (諸事情により)Salesforceの機能(Apexなど)が使えない

実現方法

Lightning Aura Componentは自身のiframe内のVisualforceとしか通信ができません。今回の場合、通信先VisualforceはLightning Aura Component外に存在します。よって、仲介用のVisualforceを用意し、そのVisualforceを介してCTIアダプタ内のVisualforceと通信を行います。

実装

以下に実装内容を記載します。

Lightning Aura Componentと自信のiframe内のVisualforceで通信

@hrk623さんがすでに詳細な説明をQiitaの記事に投稿しています。Lightning Aura Componentの実装はそちらを参考にしてください。Lightning Aura Component内に仲介Visualforceを埋め込みます。本記事内では埋め込むVisualforceを「proxy.vfp」とします。

CTIアダプタ(Visualforce)と仲介用Visualforce間の通信

Salesforce Lightningのため、CTIアダプタとメッセージ交換するためのSalesforce API 1が使用できません。JavaScriptのWeb Messaging APIを使用します。

Salesforceは複数のiframeで構成されているようです。単純にpostMessageするだけではメッセージが届きません。まず親Windowオブジェクトを取得し、そこから子iframe全てに対してpostMessageを実行します。SalesforceのUIの実装が今後どうなるかわかりませんので、iframeがネストされていることも念の為考慮します。

以下はCTIアダプタ内のVisualforceとなります。

ctiAdoptor.vfp
<apex:page>
<button type="button" onclick="sendMsgToProxyVF();">Send Message To Proxy VF</button>
<script>
console.log = console.log.bind(console, '[CTIAdaptor]'); // ログの見易さのため部分適用
let proxyVFPort;

function sendMsgToProxyVF() {
    proxyVFPort.postMessage("hello, I'm CTI Adaptor.");
}

function connectListener(e) {
    if (e.data === 'CONNECT') {
        console.log('Receive connect request message.');
        // 送信元でMessageChannelを生成しても可能、そちらの方が実装は楽です。
        // 今回はブロードキャストのように子iframe全てにメッセージが送信されますので、接続先で生成するようにしました。
        const msgChannel = new MessageChannel();
        proxyVFPort = msgChannel.port1;
        msgChannel.port1.onmessage = function(e) {
            console.log('Receive message');
        };
        e.source.postMessage('CONNECTED', e.origin, [ msgChannel.port2 ]);
        window.removeEventListener('message', connectListener);
    }
}

window.addEventListener('message', connectListener);
</script>
</apex:page>

以下は仲介用Visualforceとなります。Lightning Aura Componentのiframe内に埋め込まれます。

proxy.vfp
<apex:page>
<button type="button" onclick="connectToCTIAdaptor();">Connect to CTI Adaptor</button>
<button type="button" onclick="sendToCTIAdaptor();">Send Message to CTI Adaptor</button>
<script>
console.log = console.log.bind(console, '[Proxy]'); // ログの見易さのため部分適用
let ctiAdaptorPort;

function sendToCTIAdaptor() {
    ctiAdaptorPort.postMessage("hello, I'm Proxy.");
}

function connectToCTIAdaptor() {
    const frameArr = window.top.frames;
    for (let i = 0; i < frameArr.length; i++) {
        console.log('connect to CTI Adaptor.');
        // サンプルのため、第3引数に送信先オリジンを指定しません。実際の実装ではきちんと設定してください。
        postMessageRecursive(frameArr[i], 'CONNECT', '*');
    }
}

// iframe内にネストされたiframeがある場合を考慮して、再帰的にメッセージ送信を行います
function postMessageRecursive(iframe, msg, targetOrigin) {
    iframe.postMessage(msg, targetOrigin);
    if (iframe.frames.length > 0) {
        // window.framesはiterableオブジェクトではないためfor...of構文は使用できません
        for (let i = 0; i < iframe.frames.length; i++) {
            postMessageRecursive(iframe.frames[i], msg, targetOrigin);
        }
    }
}

function connectedListener(e) {
    if (e.data === 'CONNECTED') {
        console.log('Success to connect.');
        ctiAdaptorPort = e.ports[0];
        ctiAdaptorPort.onmessage = function(e) {
            console.log('Receive message.');
        }
        window.removeEventListener('message', connectedListener);
    }
}

// 今回はMessageChannelは接続先で生成します。
// 接続先でMessageChannelを生成してそれを利用するため、メッセージを待ち受けます。
window.addEventListener('message', connectedListener);
</script>
</apex:page>

Lightning Componentとの通信も実装した仲介用Visualforceでは、以下のようにしてメッセージをバケツリレーするイメージです。

class ProxySession {
    constructor(lcPort, ctiAdaptorPort) {
        lcPort.onmessage = function(e) {
            ctiAdaptorPort.postMessage(e.data);
        };
        ctiAdaptorPort.onmessage = function(e) {
            lcPort.postMessage(e.data);
        };
    }
}

参考


  1. Salesforce Classicの場合、CTIアダプタとメッセージ交換するAPIが用意されています。 

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1