|
|
|
package com.fr.design.jxbrowser;
|
|
|
|
|
|
|
|
import com.fr.design.DesignerEnvManager;
|
|
|
|
import com.fr.design.ui.ModernUIConstants;
|
|
|
|
import com.fr.log.FineLoggerFactory;
|
|
|
|
import com.fr.stable.CommonUtils;
|
|
|
|
import com.fr.value.ClearableLazyValue;
|
|
|
|
import com.fr.web.struct.AssembleComponent;
|
|
|
|
import com.teamdev.jxbrowser.engine.ChromiumBinariesExtractionException;
|
|
|
|
import com.teamdev.jxbrowser.engine.Engine;
|
|
|
|
import com.teamdev.jxbrowser.engine.EngineOptions;
|
|
|
|
import com.teamdev.jxbrowser.engine.RenderingMode;
|
|
|
|
import com.teamdev.jxbrowser.engine.event.EngineCrashed;
|
|
|
|
import com.teamdev.jxbrowser.net.HttpHeader;
|
|
|
|
import com.teamdev.jxbrowser.net.Network;
|
|
|
|
import com.teamdev.jxbrowser.net.ResourceType;
|
|
|
|
import com.teamdev.jxbrowser.net.Scheme;
|
|
|
|
import com.teamdev.jxbrowser.net.UrlRequest;
|
|
|
|
import com.teamdev.jxbrowser.net.callback.BeforeStartTransactionCallback;
|
|
|
|
import com.teamdev.jxbrowser.net.callback.VerifyCertificateCallback;
|
|
|
|
import com.teamdev.jxbrowser.os.Environment;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 可重复启动的 Jxbrowser 引擎
|
|
|
|
* 手动创建的引擎,应当自己负责管理声明周期 {@link #newInstance()}
|
|
|
|
* 单例的引擎,由系统管理生命周期,使用后仅需清理browser和map等数据
|
|
|
|
* {@link #getEngine()} 和 {@link #getPublicEngineInstance()}
|
|
|
|
*
|
|
|
|
* @author vito
|
|
|
|
* @since 11.0
|
|
|
|
* Created on 2023/6/8
|
|
|
|
*/
|
|
|
|
public class JxEngine {
|
|
|
|
private static final String SPLIT = ";";
|
|
|
|
|
|
|
|
private static final JxEngine INSTANCE = new JxEngine();
|
|
|
|
|
|
|
|
private AssembleComponent component;
|
|
|
|
private Map<String, String> parameterMap = Collections.emptyMap();
|
|
|
|
private boolean disableWebSecurity = false;
|
|
|
|
|
|
|
|
|
|
|
|
private final ClearableLazyValue<Engine> ENGINE = ClearableLazyValue.create(() -> {
|
|
|
|
EngineOptions.Builder builder = EngineOptions
|
|
|
|
.newBuilder(RenderingMode.HARDWARE_ACCELERATED)
|
|
|
|
.addSwitch("--disable-google-traffic")
|
|
|
|
.addScheme(Scheme.of(ModernUIConstants.EMB_TAG),
|
|
|
|
new NxInterceptRequestCallback(this::getComponent, this::getParameterMap));
|
|
|
|
String options = System.getProperty("jxbrowser.chrome.setup.options");
|
|
|
|
for (String s : options.split(SPLIT)) {
|
|
|
|
builder.addSwitch(s);
|
|
|
|
}
|
|
|
|
if (disableWebSecurity) {
|
|
|
|
builder.addSwitch("--disable-web-security");
|
|
|
|
}
|
|
|
|
Engine engine;
|
|
|
|
try {
|
|
|
|
engine = Engine.newInstance(builder.build());
|
|
|
|
} catch (ChromiumBinariesExtractionException e) {
|
|
|
|
Path chromiumDir = Paths.get(System.getProperty("jxbrowser.chromium.dir", Environment.defaultChromiumDir().toString()));
|
|
|
|
if (CommonUtils.deleteFile(chromiumDir.toFile())) {
|
|
|
|
FineLoggerFactory.getLogger().warn("[jxbrowser]Retry start engine success after delete chromium dir manually: {}", chromiumDir);
|
|
|
|
engine = Engine.newInstance(builder.build());
|
|
|
|
} else {
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
engine.on(EngineCrashed.class, (event) -> {
|
|
|
|
FineLoggerFactory.getLogger().error("jxBrowser engine crashed with exitCode: {}", event.exitCode());
|
|
|
|
event.engine().close();
|
|
|
|
});
|
|
|
|
if (DesignerEnvManager.getEnvManager().isOpenDebug()
|
|
|
|
|| Boolean.parseBoolean(System.getProperty("jxbrowser.verify.vertificate.prohibit"))) {
|
|
|
|
// 调试模式下,禁止HTTPS证书验证,使得可以正常访问商城测试服务器等
|
|
|
|
Network network = engine.network();
|
|
|
|
network.set(VerifyCertificateCallback.class, params -> VerifyCertificateCallback.Response.valid());
|
|
|
|
}
|
|
|
|
return engine;
|
|
|
|
});
|
|
|
|
|
|
|
|
public JxEngine() {
|
|
|
|
}
|
|
|
|
|
|
|
|
public JxEngine(boolean disableWebSecurity) {
|
|
|
|
this.disableWebSecurity = disableWebSecurity;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Map<String, String> getParameterMap() {
|
|
|
|
return Collections.unmodifiableMap(parameterMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setMap(Map<String, String> parameterMap) {
|
|
|
|
if (parameterMap == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.parameterMap = parameterMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 清理map
|
|
|
|
*/
|
|
|
|
public void clearMap() {
|
|
|
|
this.parameterMap = Collections.emptyMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
public AssembleComponent getComponent() {
|
|
|
|
return component;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setComponent(AssembleComponent component) {
|
|
|
|
this.component = component;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 清理component
|
|
|
|
*/
|
|
|
|
public void clearComponent() {
|
|
|
|
this.component = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取单例引擎包装,能够更新渲染
|
|
|
|
* 从单例获取的引擎不用负责关闭,
|
|
|
|
* 应用系统管理声明周期
|
|
|
|
*
|
|
|
|
* @return jxbrowser 引擎包装类
|
|
|
|
*/
|
|
|
|
public static JxEngine getInstance() {
|
|
|
|
return INSTANCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取公共引擎,公共引擎使用后不用关闭引擎,但需要自己管理 browser。
|
|
|
|
* 应用系统管理引擎生命周期
|
|
|
|
*
|
|
|
|
* @return 引擎
|
|
|
|
*/
|
|
|
|
@NotNull
|
|
|
|
public Engine getEngine() {
|
|
|
|
return ENGINE.getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 是否禁用安全属性
|
|
|
|
* 注:对客户端来说,安全属性可以忽略
|
|
|
|
*
|
|
|
|
* @return 是否禁用
|
|
|
|
*/
|
|
|
|
public boolean isDisableWebSecurity() {
|
|
|
|
return disableWebSecurity;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 添加XHR请求头
|
|
|
|
*
|
|
|
|
* @param headers 请求头
|
|
|
|
*/
|
|
|
|
public void addXHRHeaders(Map<String, String> headers) {
|
|
|
|
Network network = ENGINE.getValue().network();
|
|
|
|
network.set(BeforeStartTransactionCallback.class, (params) -> {
|
|
|
|
UrlRequest urlRequest = params.urlRequest();
|
|
|
|
ResourceType resourceType = urlRequest.resourceType();
|
|
|
|
if (resourceType == ResourceType.XHR) {
|
|
|
|
List<HttpHeader> httpHeaders = new ArrayList<>(params.httpHeaders());
|
|
|
|
for (Map.Entry<String, String> header : headers.entrySet()) {
|
|
|
|
httpHeaders.add(HttpHeader.of(header.getKey(), header.getValue()));
|
|
|
|
}
|
|
|
|
return BeforeStartTransactionCallback.Response.override(httpHeaders);
|
|
|
|
} else {
|
|
|
|
return BeforeStartTransactionCallback.Response.proceed();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 关闭引擎
|
|
|
|
*/
|
|
|
|
public void close() {
|
|
|
|
ENGINE.getValue().close();
|
|
|
|
ENGINE.drop();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取公共引擎,公共引擎使用后不用关闭引擎,但需要自己管理 browser。
|
|
|
|
* 应用系统管理引擎生命周期
|
|
|
|
*
|
|
|
|
* @return 引擎
|
|
|
|
*/
|
|
|
|
public static Engine getPublicEngineInstance() {
|
|
|
|
return getInstance().ENGINE.getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 创建一个新的引擎,创建引擎使用后需负责关闭引擎
|
|
|
|
* 但可以独立使用 map 和 component
|
|
|
|
*
|
|
|
|
* @return 引擎
|
|
|
|
*/
|
|
|
|
public static JxEngine newInstance() {
|
|
|
|
return new JxEngine();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 创建一个新的引擎,创建引擎使用后需负责关闭引擎
|
|
|
|
* 但可以独立使用 map 和 component
|
|
|
|
*
|
|
|
|
* @return 引擎
|
|
|
|
*/
|
|
|
|
public static JxEngine newInstance(boolean disableWebSecurity) {
|
|
|
|
return new JxEngine(disableWebSecurity);
|
|
|
|
}
|
|
|
|
}
|