v1.0.1: fully reflection-based browser (EmbeddedBrowser/EmbeddedJsBridge), zero compile-time JCEF deps; panel never blank
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package com.harmness.toolwindow
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.util.function.Function
|
||||
import javax.swing.JComponent
|
||||
|
||||
/**
|
||||
* JCEF JS↔Java 桥的反射封装。
|
||||
*
|
||||
* 负责两件事:
|
||||
* 1. 通过反射创建 JBCefJSQuery 并注册 handler(把网页发来的字符串请求转发给 [onRequest])
|
||||
* 2. 通过反射调用 JBCefJSQuery.inject() 生成注入到页面的 JS 代码
|
||||
*
|
||||
* 与 [EmbeddedBrowser] 一样,编译期零 JCEF 依赖。类缺失/调用失败时
|
||||
* 仅返回 null / 空串,不影响浏览器主体功能。
|
||||
*/
|
||||
class EmbeddedJsBridge private constructor(
|
||||
private val queryInstance: Any,
|
||||
private val onRequest: (String) -> Any?
|
||||
) {
|
||||
|
||||
/**
|
||||
* 返回可注入到页面 JS 的代码片段(调用插件 handler),
|
||||
* 失败返回空串。
|
||||
*/
|
||||
fun injectJs(): String = try {
|
||||
val m = queryInstance.javaClass.getMethod(
|
||||
"inject", String::class.java, String::class.java, String::class.java
|
||||
)
|
||||
(m.invoke(queryInstance, "payload.query",
|
||||
"function(response){ if (payload.callbacks && payload.callbacks.onSuccess) payload.callbacks.onSuccess(response); }",
|
||||
"function(code,msg){ if (payload.callbacks && payload.callbacks.onFailure) payload.callbacks.onFailure(code,msg); }"
|
||||
) as? String) ?: ""
|
||||
} catch (t: Throwable) {
|
||||
log.warn("injectJs failed", t)
|
||||
""
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
try {
|
||||
queryInstance.javaClass.getMethod("dispose").invoke(queryInstance)
|
||||
} catch (t: Throwable) {
|
||||
log.warn("bridge dispose failed", t)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val log = Logger.getInstance(EmbeddedJsBridge::class.java)
|
||||
|
||||
/**
|
||||
* 为已创建的 [browser] 建立 JS 桥。
|
||||
* @return 成功返回桥对象;失败返回 null(浏览器仍可用,仅网页无法调用插件 API)
|
||||
*/
|
||||
fun create(browser: EmbeddedBrowser, onRequest: (String) -> Any?): EmbeddedJsBridge? {
|
||||
try {
|
||||
val queryClass = Class.forName("com.intellij.ui.jcef.JBCefJSQuery")
|
||||
// create(JBCefBrowserBase) — 用可赋值参数类型查找
|
||||
val browserInst = browser.instance
|
||||
val createMethod = queryClass.methods.firstOrNull { m ->
|
||||
m.name == "create" && m.parameterCount == 1 &&
|
||||
m.parameterTypes[0].isAssignableFrom(browserInst.javaClass)
|
||||
} ?: return null
|
||||
val queryInstance = createMethod.invoke(null, browserInst)
|
||||
|
||||
// addHandler(java.util.function.Function<String, Response>)
|
||||
val handlerFn = Function<String, Any?> { req -> onRequest(req ?: "") }
|
||||
val addMethod = queryClass.methods.firstOrNull { m ->
|
||||
m.name == "addHandler" && m.parameterCount == 1 &&
|
||||
m.parameterTypes[0] == Function::class.java
|
||||
} ?: return null
|
||||
addMethod.invoke(queryInstance, handlerFn)
|
||||
|
||||
return EmbeddedJsBridge(queryInstance, onRequest)
|
||||
} catch (t: Throwable) {
|
||||
val real = when (t) {
|
||||
is InvocationTargetException -> t.targetException ?: t
|
||||
else -> t
|
||||
}
|
||||
log.warn("EmbeddedJsBridge.create failed: ${real.javaClass.simpleName}: ${real.message}", real)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user