This commit is contained in:
xyf-mac 2021-11-04 21:01:33 +08:00
parent 50069b54dc
commit cff5edf263
9 changed files with 255 additions and 117 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "app", "name": "app",
"version": "0.1.0", "version": "0.1.1",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",

View File

@ -1,83 +1,166 @@
import {Page, PluginEvent, Msg} from "@/core/types"; import {Msg, Page, PluginEvent} from "@/core/types";
let Devtools: chrome.runtime.Port | null = null; console.log("on background")
let Content: chrome.runtime.Port | null = null;
console.log('on background')
chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => { class PortMan {
switch (port.name) { content: chrome.runtime.Port | null = null;
case Page.Devtools: { devtools: chrome.runtime.Port | null = null;
Devtools = port; public id: number | null = null;// tab.id作为唯一标识
onPortConnect(port, public title: string = "";
(data: PluginEvent) => { public url: string = "";
// 从devtools过来的消息统一派发到Content中 private mgr: PortManagement | null = null;
if (PluginEvent.check(data, Page.Devtools, Page.Background)) {
PluginEvent.reset(data, Page.Background, Page.Content);
Content && Content.postMessage(data)
}
},
() => {
Devtools = null;
})
break;
}
case Page.Content: {
Content = port;
onPortConnect(port,
() => {
}, constructor(mgr: PortManagement, {id, url, title}: any) {
() => { this.mgr = mgr;
Content = null; this.id = id;
this.url = url;
this.title = title;
}
}) private onPortConnect(port: chrome.runtime.Port, onMsg: Function, onDisconnect: Function) {
break port.onMessage.addListener((data: any, sender: any) => {
console.log(`%c[Connect-Message] ${sender.name}\n${JSON.stringify(data)}`, "color:green;")
// 如果多个页面都监听 onMessage 事件,对于某一次事件只有第一次调用 sendResponse() 能成功发出回应,所有其他回应将被忽略。
// sender.postMessage(data);
onMsg && onMsg(data);
});
port.onDisconnect.addListener((port: chrome.runtime.Port) => {
console.log(`%c[Connect-Dis] ${port.name}`, "color:red");
onDisconnect && onDisconnect()
});
}
dealConnect(port: chrome.runtime.Port) {
switch (port.name) {
case Page.Content: {
this.content = port;
this.onPortConnect(port,
(data: PluginEvent) => {
if (data.target === Page.Devtools) {
this.sendDevtoolMsg(data);
}
},
() => {
this.content = null;
this.checkValid();
})
break;
}
case Page.Devtools: {
this.devtools = port;
this.onPortConnect(port,
(data: PluginEvent) => {
// 从devtools过来的消息统一派发到Content中
if (PluginEvent.check(data, Page.Devtools, Page.Background)) {
PluginEvent.reset(data, Page.Background, Page.Content);
this.content?.postMessage(data)
}
},
() => {
this.devtools = null;
this.checkValid();
})
break
}
} }
} }
});
function onPortConnect(port: chrome.runtime.Port, onMsg: Function, onDisconnect: Function) { checkValid() {
console.log(`%c[Connect] ${port.name}`, "color:blue;"); if (!this.devtools && !this.content) {
port.onMessage.addListener((data: any, sender: any) => { this.mgr?.remove(this);
console.log(`%c[Connect-Message] ${sender.name}\n${JSON.stringify(data)}`, "color:green;") }
// 如果多个页面都监听 onMessage 事件,对于某一次事件只有第一次调用 sendResponse() 能成功发出回应,所有其他回应将被忽略。 }
// sender.postMessage(data);
onMsg && onMsg(data); sendContentMsg(data: PluginEvent) {
}); this.content?.postMessage(data);
port.onDisconnect.addListener((port: chrome.runtime.Port) => { }
console.log(`%c[Connect-Dis] ${port.name}`, "color:red");
onDisconnect && onDisconnect() sendDevtoolMsg(data: PluginEvent) {
}); this.devtools?.postMessage(data)
}
} }
class PortManagement {
port: Array<PortMan> = [];
// background.js 更像是一个主进程,负责整个插件的调度,生命周期和chrome保持一致 constructor() {
// 监听来自content.js发来的事件将消息转发到devtools this.initConnect();
chrome.runtime.onMessage.addListener((request: PluginEvent, sender: any, sendResponse: any) => { chrome.runtime.onMessage.addListener((request: PluginEvent, sender: any, sendResponse: any) => {
if (PluginEvent.check(request, Page.Content, Page.Background)) { const tabID = sender.tab.id;
PluginEvent.reset(request, Page.Background, Page.Devtools) const portMan: PortMan | undefined = this.find(tabID);
console.log(`%c[Message]url:${sender.url}]\n${JSON.stringify(request)}`, 'color:green') if (portMan) {
sendResponse && sendResponse(request); if (PluginEvent.check(request, Page.Content, Page.Background)) {
Devtools && Devtools.postMessage(request); // 监听来自content.js发来的事件将消息转发到devtools
PluginEvent.reset(request, Page.Background, Page.Devtools)
console.log(`%c[Message]url:${sender.url}]\n${JSON.stringify(request)}`, "color:green")
portMan.sendDevtoolMsg(request);
}
}
})
chrome.tabs.onActivated.addListener(({tabId, windowId}) => {
})
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
// 页面发生刷新,通知重新生成数据
if (changeInfo.status === "complete") {
const {id} = tab;
// -1为自己
if (id && id > -1) {
let portMan = this.find(id);
if (portMan) {
let data = new PluginEvent(
Page.Background,
Page.Content,
Msg.Test,
{url: tab.url}
);
// portMan.sendContentMsg(data);
}
}
}
})
}
initConnect() {
chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => {
if (port.name === Page.Devtools) {
// devtool链接过来没有port.sender.tab
chrome.tabs.getSelected((tab: chrome.tabs.Tab) => {
this._onConnect(tab, port)
})
} else {
const tab: chrome.tabs.Tab | undefined = port.sender?.tab;
if (tab) {
this._onConnect(tab, port)
}
}
})
}
private _onConnect(tab: chrome.tabs.Tab, port: chrome.runtime.Port) {
const {id, title, url} = tab;
if (id !== undefined && id > -1) {
let portMan: PortMan | undefined = this.find(id)
if (!portMan) {
portMan = new PortMan(this, {id, title, url});
this.port.push(portMan);
}
portMan.dealConnect(port);
} }
} }
);
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { find(id: number): PortMan | undefined {
console.warn(changeInfo.status) return this.port.find(el => el.id === id)
if (changeInfo.status === "complete") { }
// 加载新的url
if (Content) { remove(item: PortMan) {
let data = new PluginEvent( let index = this.port.findIndex(el => el === item)
Page.Background, if (index > -1) {
Page.Content, this.port.splice(index, 1)
Msg.UrlChange,
{url: tab.favIconUrl}
);
Content.postMessage(data);
} }
} }
}) }
(window as any).backgroundInstance = new PortManagement();
function createPluginMenus() { function createPluginMenus() {
const menus = []; const menus = [];

View File

@ -5,37 +5,57 @@ import {Msg, Page, PluginEvent} from "@/core/types";
injectScript("js/inject.js"); injectScript("js/inject.js");
// 和background.js保持长连接通讯 class Content {
let conn = chrome.runtime.connect({name: Page.Content}) private connect: chrome.runtime.Port | null = null;
conn.onMessage.addListener((data: PluginEvent, sender) => {
// 将background.js的消息返回到injection.js constructor() {
if (PluginEvent.check(data, Page.Background, Page.Content)) { // 接受来自inject.js的消息数据,然后中转到background.js
// console.log(`%c[Connect-Message] ${JSON.stringify(data)}`, "color:green;") window.addEventListener("message", (event) => {
console.log('[Connect-Message]: ', data); let data: PluginEvent = event.data;
PluginEvent.reset(data, Page.Content, Page.Inject) if (PluginEvent.check(data, Page.Inject, Page.Content)) {
window.postMessage(data, "*"); console.log("[Window-Message]: ", data);
PluginEvent.reset(data, Page.Content, Page.Devtools)
this.connect?.postMessage(data)
}
}, false);
} }
})
// 接受来自inject.js的消息数据,然后中转到background.js // 和background.js保持长连接通讯background和content的交互也要通过这个链接进行通讯
window.addEventListener('message', function (event) { private connectToBackground() {
let data: PluginEvent = event.data; this.connect = chrome.runtime.connect({name: Page.Content})
if (PluginEvent.check(data, Page.Inject, Page.Content)) { this.connect.onMessage.addListener((data: PluginEvent, sender) => {
// console.log(`%c[Window-Message] ${JSON.stringify(data)}`, "color:green;"); if (PluginEvent.check(data, Page.Background, Page.Content)) {
console.log('[Window-Message]: ', data); // console.log(`%c[Connect-Message] ${JSON.stringify(data)}`, "color:green;")
PluginEvent.reset(data, Page.Content, Page.Background) console.log("[Connect-Message]: ", data);
chrome.runtime.sendMessage(data); PluginEvent.reset(data, Page.Content, Page.Inject)
window.postMessage(data, "*");
}
})
} }
}, false);
private sendMessageToBackground(data: PluginEvent) {
if (this.connect) {
this.connect.postMessage(data);
}
}
let gameCanvas = document.querySelector("#GameCanvas"); async run() {
if (!gameCanvas) { this.connectToBackground();
let sendData = new PluginEvent(Page.Content, Page.Background, Msg.Support, { this.checkGame();
support: false, }
msg: "未发现GameCanvas,不支持调试游戏!"
}) private checkGame() {
chrome.runtime.sendMessage(sendData, (ret) => { let gameCanvas = document.querySelector("#GameCanvas");
console.log(ret) if (!gameCanvas) {
}); let sendData = new PluginEvent(Page.Content, Page.Devtools, Msg.Support, {
support: false,
msg: "未发现GameCanvas,不支持调试游戏!"
})
this.sendMessageToBackground(sendData)
}
}
} }
const content = new Content();
content.run();

View File

@ -13,7 +13,8 @@ export enum Msg {
Support = "game-support",// 游戏支持信息 Support = "game-support",// 游戏支持信息
MemoryInfo = "memory-info",// MemoryInfo = "memory-info",//
TabsInfo = "tabs_info", // 当前页面信息 TabsInfo = "tabs_info", // 当前页面信息
UrlChange = "url_change", // 网址发生变化 GetTabID = "GetTabID", // 获取页面ID
Test='Test',
SetProperty = "set-property", // 设置node属性 SetProperty = "set-property", // 设置node属性
UpdateProperty = 'update-property', // 更新属性 UpdateProperty = 'update-property', // 更新属性
} }
@ -45,7 +46,7 @@ export class PluginEvent {
this.source = source; this.source = source;
this.target = target; this.target = target;
this.msg = msg; this.msg = msg;
this.data = data || null; this.data = data;
} else { } else {
console.warn(`无效的target: ${target}`) console.warn(`无效的target: ${target}`)
} }

View File

@ -2,12 +2,42 @@ export function injectScript(url: string) {
if (chrome && chrome.extension && chrome.extension.getURL) { if (chrome && chrome.extension && chrome.extension.getURL) {
let content = chrome.extension.getURL(url) let content = chrome.extension.getURL(url)
console.log(`[cc-inspector]注入脚本:${content}`); console.log(`[cc-inspector]注入脚本:${content}`);
let script = document.createElement('script') const script = document.createElement("script")
script.setAttribute('type', 'text/javascript') script.setAttribute("type", "text/javascript")
script.setAttribute('src', content) script.setAttribute("src", content)
script.onload = function () { script.onload = function () {
document.body.removeChild(script); document.body.removeChild(script);
} }
document.body.appendChild(script) document.body.appendChild(script)
} }
} }
interface LogOptions {
data: any;
flag?: string;
color?: "red" | "blue";
}
export function log(options: LogOptions) {
const data: any = options.data;
const time = new Date().toLocaleString()
let log = ""
if (typeof data === "string") {
log = data;
} else if (typeof data === "object") {
log = JSON.stringify(data)
}
let str = "";
if (options.flag) {
str = `[${time}][${options.flag}]: ${log} `;
} else {
str = `[${time}]: ${log} `;
}
if (options.color) {
console.log(`%c${str}`, `color:${options.color};`)
} else {
console.log(str);
}
}

View File

@ -4,10 +4,14 @@ class ConnectBackground {
connect: chrome.runtime.Port | null = null; connect: chrome.runtime.Port | null = null;
constructor() { constructor() {
this._initConnect();
}
private _initConnect() {
if (chrome && chrome.runtime) { if (chrome && chrome.runtime) {
this.connect = chrome.runtime.connect({name: Page.Devtools}); this.connect = chrome.runtime.connect({name: Page.Devtools});
this.connect.onDisconnect.addListener(() => { this.connect.onDisconnect.addListener(() => {
console.log(`%c[Connect-Dis]`, 'color:red;') console.log(`%c[Connect-Dis]`, "color:red;")
this.connect = null; this.connect = null;
}) })
} }
@ -21,12 +25,14 @@ class ConnectBackground {
} }
} }
postMessageToBackground(msg: Msg, data?: any ) { postMessageToBackground(msg: Msg, data?: any) {
if (this.connect) { if (this.connect) {
let sendData = new PluginEvent(Page.Devtools, Page.Background, msg, data) let sendData = new PluginEvent(Page.Devtools, Page.Background, msg, data)
this.connect.postMessage(sendData) this.connect.postMessage(sendData)
} else { } else {
console.warn('没有和background建立链接') console.warn("重新和background建立链接")
this._initConnect();
this.postMessageToBackground(msg, data)
} }
} }

View File

@ -47,7 +47,6 @@ class CCInspector {
console.log(`%c[Inject] ${JSON.stringify(pluginEvent)}`, "color:green;"); console.log(`%c[Inject] ${JSON.stringify(pluginEvent)}`, "color:green;");
PluginEvent.finish(pluginEvent) PluginEvent.finish(pluginEvent)
switch (pluginEvent.msg) { switch (pluginEvent.msg) {
case Msg.UrlChange:
case Msg.Support: { case Msg.Support: {
let isCocosGame = this._isCocosGame(); let isCocosGame = this._isCocosGame();
this.notifySupportGame(isCocosGame) this.notifySupportGame(isCocosGame)

View File

@ -15,7 +15,7 @@ export function init() {
panel.onShown.addListener((window) => { panel.onShown.addListener((window) => {
// 面板显示查询是否是cocos游戏 // 面板显示查询是否是cocos游戏
console.log("panel show"); console.log("panel show");
connectBackground.postMessageToBackground(Msg.Support, null) // connectBackground.postMessageToBackground(Msg.Support, null)
}); });
panel.onHidden.addListener(() => { panel.onHidden.addListener(() => {
// 面板隐藏 // 面板隐藏

View File

@ -28,7 +28,7 @@
@node-expand="onNodeExpand" @node-expand="onNodeExpand"
@node-collapse="onNodeCollapse" @node-collapse="onNodeCollapse"
@node-click="handleNodeClick"> @node-click="handleNodeClick">
<!-- :render-content="renderContent"--> <!-- :render-content="renderContent"-->
<span slot-scope="{node,data}" class="leaf" :class="data.active?'leaf-show':'leaf-hide'"> <span slot-scope="{node,data}" class="leaf" :class="data.active?'leaf-show':'leaf-hide'">
<span>{{ node.label }}</span> <span>{{ node.label }}</span>
@ -52,10 +52,10 @@
import Vue from "vue"; import Vue from "vue";
import {Component} from "vue-property-decorator"; import {Component} from "vue-property-decorator";
import properties from "./propertys.vue"; import properties from "./propertys.vue";
import {Msg, Page, PluginEvent} from '@/core/types' import {Msg, Page, PluginEvent} from "@/core/types"
import {connectBackground} from "@/devtools/connectBackground"; import {connectBackground} from "@/devtools/connectBackground";
import {EngineData, Info, TreeData} from "@/devtools/data"; import {EngineData, Info, TreeData} from "@/devtools/data";
import Bus, {BusMsg} from '@/devtools/bus'; import Bus, {BusMsg} from "@/devtools/bus";
@Component({ @Component({
components: { components: {
@ -130,7 +130,7 @@ export default class Index extends Vue {
renderContent(h: Function, options: any) { renderContent(h: Function, options: any) {
let {node, data, store} = options; let {node, data, store} = options;
return h('span', {class:''}, data.name) return h("span", {class: ""}, data.name)
// return(<span>1111</span>) // return(<span>1111</span>)
} }
@ -184,14 +184,12 @@ export default class Index extends Vue {
if (!data) { if (!data) {
return; return;
} }
if (PluginEvent.check(data, Page.Background, Page.Devtools)) { if (data.target === Page.Devtools) {
debugger
console.log(`[Devtools] ${JSON.stringify(data)}`); console.log(`[Devtools] ${JSON.stringify(data)}`);
PluginEvent.finish(data); PluginEvent.finish(data);
let eventData: any = data.data; let eventData: any = data.data;
switch (data.msg) { switch (data.msg) {
case Msg.UrlChange: {
break;
}
case Msg.TreeInfo: { case Msg.TreeInfo: {
this._onMsgListInfo(eventData as Array<TreeData>); this._onMsgListInfo(eventData as Array<TreeData>);
break; break;
@ -238,10 +236,10 @@ export default class Index extends Vue {
circle(this.treeData) circle(this.treeData)
let ret = treeArray.find(el => el.uuid === uuid); let ret = treeArray.find(el => el.uuid === uuid);
if (ret) { if (ret) {
if (key === 'name') { if (key === "name") {
ret.name = value; ret.name = value;
} }
if (key === 'active') { if (key === "active") {
ret.active = !!value; ret.active = !!value;
} }
} }
@ -287,7 +285,7 @@ export default class Index extends Vue {
} }
_inspectedCode() { _inspectedCode() {
let injectCode = ''; let injectCode = "";
chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => { chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => {
if (isException) { if (isException) {
console.error(isException); console.error(isException);
@ -302,6 +300,7 @@ export default class Index extends Vue {
} }
onBtnClickUpdatePage() { onBtnClickUpdatePage() {
debugger
this.runToContentScript(Msg.Support); this.runToContentScript(Msg.Support);
} }
@ -310,13 +309,13 @@ export default class Index extends Vue {
} }
onNodeExpand(data: TreeData) { onNodeExpand(data: TreeData) {
if (data.hasOwnProperty('uuid') && data.uuid) { if (data.hasOwnProperty("uuid") && data.uuid) {
this.expandedKeys.push(data.uuid) this.expandedKeys.push(data.uuid)
} }
} }
onNodeCollapse(data: TreeData) { onNodeCollapse(data: TreeData) {
if (data.hasOwnProperty('uuid')) { if (data.hasOwnProperty("uuid")) {
let index = this.expandedKeys.findIndex(el => el === data.uuid); let index = this.expandedKeys.findIndex(el => el === data.uuid);
if (index !== -1) { if (index !== -1) {
this.expandedKeys.splice(index, 1) this.expandedKeys.splice(index, 1)