ブラウザプラグインの開発中にスクリプトとページコンテンツを注入する通信について
ブラウザプラグインの開発中にスクリプトとページコンテンツを注入する通信について
説明
最近ではsafariブラウザ拡張および360ブラウザ拡張の開発を行っているが,従来のchrome拡張とは異なり,低バージョンのsafari(12)と低バージョンの360ブラウザでは
通信機能を実現するためには、Chromeと360の公式ドキュメントで推奨されている方法でもあるhackを比較する方法も必要です.はdom要素を作成し、このdom要素の とする.その後、このdom要素にカスタムイベント(document.createEvent(‘Event’)) を作成します.がデータを渡すときは、まず は、 を行う.
インプリメンテーション
挿入スクリプトの
以上の論理に従って、挿入スクリプトとページコンテンツの間の通信プラットフォーム(flowをタイプ宣言し、不要な削除を行う)を構築するためのクラスをカプセル化し、
ページ内容部分の使用
注入スクリプト部分の使用
説明
最近ではsafariブラウザ拡張および360ブラウザ拡張の開発を行っているが,従来のchrome拡張とは異なり,低バージョンのsafari(12)と低バージョンの360ブラウザでは
window.postMessage()
を用いて注入スクリプトとページ間の通信が成功していないことが分かった.通信機能を実現するためには、Chromeと360の公式ドキュメントで推奨されている方法でもあるhackを比較する方法も必要です.
innerText
をデータを格納媒体innerText
を更新し、キッチンというカスタムイベント(dom.dispatchEvent(event)
)dom.addEventListener()
によってイベントを傍受後、後続の動作インプリメンテーション
挿入スクリプトの
window
とページコンテンツのwindow
は、一部のブラウザで一定の分離があり、属性やメソッドを共有することはできないため、両者の相互通信を実現するには、両側にカスタムイベントを登録し、両者の間で所定のイベント名でイベントリスニングを行う必要がある.以上の論理に従って、挿入スクリプトとページコンテンツの間の通信プラットフォーム(flowをタイプ宣言し、不要な削除を行う)を構築するためのクラスをカプセル化し、
window.postMessage
のapiを模倣し、window.postMessage
が利用可能であることを優先し、使用できない場合はdomノードを使用して中継する方法を実現した.// @flow
/*
*
* */
class CommunicationPlatform {
communicationPointId: string;
communicationPoint: HTMLDivElement;
fromEventName: string;
toEventName: string;
communicationEvent: CustomEvent;
isPostMessageUseful: boolean;
constructor(communicationPointId: string, event: {from: string, to: string}) {
this.communicationPointId = communicationPointId;
this.communicationPoint = document.getElementById(communicationPointId);
this.isPostMessageUseful = this.judgeHasPostMessage();
// postMessage
if (!this.isPostMessageUseful) {
this.fromEventName = event.from;
this.toEventName = event.to;
this.communicationPoint && this.registerExtensionEvent();
}
}
registerExtensionEvent() {
this.communicationEvent = document.createEvent('Event');
this.communicationEvent.initEvent(this.toEventName, true, true);
}
addEventListener = (listener: (result: {data: Object}) => void) => {
if (typeof listener !== 'function') return;
if (this.isPostMessageUseful) {
return window.addEventListener('message', listener);
}
const point = this.communicationPoint;
if (point && typeof point.addEventListener === 'function') {
point.addEventListener(this.fromEventName, () => {
const eventData = this.parseEventData(point.innerText);
// window.addEventListener('message', ({data, source}) => {})
listener({data: eventData || {}, source: window});
});
}
};
postMessage = (data: Object) => {
if (this.isPostMessageUseful) {
return window.postMessage(data);
}
const point = this.communicationPoint;
if (point && typeof point.dispatchEvent === 'function') {
point.innerText = this.transferDataToString(data) || '';
point.dispatchEvent(this.communicationEvent);
}
};
// extension ,
hasPoint = (): boolean => {
return !!this.communicationPoint;
};
judgeHasPostMessage() {
let hasPostMessage = true;
try {
window.postMessage({type: 'TEST_POST_MESSAGE_USEFUL'});
} catch (e) {
hasPostMessage = false;
}
return hasPostMessage;
}
parseEventData(eventData: ?string): Object | null {
let result = null;
if (typeof eventData === 'string') {
try {
const temp = eventData; //
result = JSON.parse(temp);
} catch (err) {
console.error(err);
}
}
return result;
}
transferDataToString(data: Object): string | null {
let result = null;
try {
const temp = JSON.stringify(data); //
result = temp;
} catch (err) {
console.error(err);
}
return result;
}
}
export default CommunicationPlatform;
ページ内容部分の使用
//
const extensionCommunicationPointId = 'xxx_extension_communication_point';
const extensionCommunicationPoint = document.createElement('div');
_.set(extensionCommunicationPoint, 'id', extensionCommunicationPointId);
_.set(extensionCommunicationPoint, 'style.display', 'none'); //
document.body.appendChild(extensionCommunicationPoint);
// window
window.CommunicationPlatform = new CommunicationPlatform(extensionCommunicationPointId, {
from: 'communicationPageMessage', // ,
to: 'communicationInjectMessage', // ,
});
//
window.CommunicationPlatform.postMessage(data);
//
window.CommunicationPlatform.addEventListener((event: {source: Object, data: Object}) => {})
注入スクリプト部分の使用
const InjectCommunicationPlatform = new CommunicationPlatform(
'xxx_extension_communication_point',
{from: 'communicationInjectMessage', to: 'communicationPageMessage'},
);
const hasPoint = InjectCommunicationPlatform &&
typeof InjectCommunicationPlatform.hasPoint === 'function' &&
InjectCommunicationPlatform.hasPoint();
const hasPostMessage = InjectCommunicationPlatform.judgeHasPostMessage();
if (hasPoint || hasPostMessage) {
InjectCommunicationPlatform.postMessage(data); //
InjectCommunicationPlatform.addEventListener((event: {source: Object, data: Object}) => {}) //
}