由于工作中有需求,需要在Linux平台支持JCEF内置浏览器到Java窗口,且需要支持WebGL三维浏览。
基于此需求,就排除了DJNativeSwing和JavaFx自带的WebView,选用了JCEF技术路线。
将踩坑步骤记录如下:
1.找到Linux JCEF可用的包,由于我的项目要求是Java8环境,所以选择的是:
Release v1.0.9-78.3.9+gc7345f2+chromium-78.0.3904.108 · jcefbuild/jcefbuild · GitHub
这个源包支持java8环境;
(https://download.csdn.net/download/geminit2011/86281288)
压缩包内的目录结构是这样的
2.解压后,可以直接运行compile.sh,编译后,运行run.sh,正常情况会出现一个swing窗体。
3.可能出现的踩坑:
a.GLIBCXX版本过低
这个解决简单,升级gcc,就可以,我这里用的是gcc6.1.0
解压gcc-6.1.0.tar.xz,假定目录在/root/soft/目录(目录可以自定义)
升级指令
mv /usr/bin/gcc /usr/bin/gcc485
mv /usr/bin/g++ /usr/bin/g++485
mv /usr/bin/c++ /usr/bin/c++485
ln -s /root/soft/gcc-6.1.0/bin/gcc /usr/bin/gcc
ln -s /root/soft/gcc-6.1.0/bin/g++ /usr/bin/g++
ln -s /root/soft/gcc-6.1.0/bin/c++ /usr/bin/c++
mv /lib64/libstdc++.so.6 /lib64/libstdc++.so.6.bak
ln -s /root/soft/gcc-6.1.0/lib64/libstdc++.so.6.0.22 /lib64/libstdc++.so.6
升级完毕后执行指令:strings /lib64/libstdc++.so |grep GLIBCXX
输出的GLIBCXX有3.4.22就可以;
b.执行的时候会崩溃,报错一般是:
Offscreen rendering disabled
Using:
JCEF Version = 78.3.9.242
CEF Version = 78.3.9
Chromium Version = 78.0.3904.108
AppHandler.stateHasChanged: INITIALIZING
initialize on Thread[AWT-EventQueue-0,6,main] with library path /root/java-cef-build-bin/bin/lib/linux64
Added scheme search://
Added scheme client://
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.828133:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 1 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.830704:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 2 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
AppHandler.stateHasChanged: INITIALIZED
[0803/100412.833812:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 3 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.837619:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 4 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.840672:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 5 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.843655:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 6 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.846199:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 7 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.851683:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 8 time(s)
LaunchProcess: failed to execvp:
/root/java-cef-build-bin/bin/lib/linux64/jcef_helper
[0803/100412.855244:WARNING:gpu_process_host.cc(1220)] The GPU process has crashed 9 time(s)
[0803/100412.855281:FATAL:gpu_data_manager_impl_private.cc(986)] The display compositor is frequently crashing. Goodbye.
./run.sh: 行 13: 11622 Trace/breakpoint trap (吐核)LD_PRELOAD=$LIB_PATH/libcef.so java -cp "./bin:./bin/*" -Djava.library.path=$LIB_PATH tests.detailed.MainFrame "$@"
这种一般是linux权限问题,我的解决办法是,执行chmod +x -R java-cef-build-bin/
赋予文件夹执行权限【这个地方踩坑解决了1天,各种搜索材料…】
4.代码集成
简单的写了一个Java Project工程,拷贝java-cef-build-bin/bin目录下的jar到工程的环境依赖;
linux需要特殊处理,在初始化之前调用CefApp.startup();
附测试例子代码:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.OS;
import org.cef.browser.CefBrowser;
import org.cef.browser.CefMessageRouter;
import org.cef.browser.CefMessageRouter.CefMessageRouterConfig;
/**
* Chrome 浏览器内嵌Panel
* 内嵌浏览器属于重量级Canvas,Chromium属于耗资源的控件,不能随意初始化
*
* @author Gui Lei
*
*/
public class ChromePanel extends JPanel
{
private static final long serialVersionUID = 1L;
private static CefApp cefApp_;
private CefClient client_;
private CefBrowser browser_;
private Component browerUI_;
private Dimension size = new Dimension(800, 600);
static
{
CefSettings settings = new CefSettings();
if(OS.isLinux())
{
//linux的特殊处理
CefApp.startup();
}
cefApp_ = CefApp.getInstance(settings);
}
/**
* 进入页面之前,添加js交互(这里做登录用)
* @param client
*/
public void jsActive(CefClient client)
{
CefMessageRouterConfig cmrc = new CefMessageRouterConfig("java", "javaCancel");
CefMessageRouter cmr = CefMessageRouter.create(cmrc);
client.addMessageRouter(cmr);
}
/**
*
* @param startURL
*/
public ChromePanel(String startURL)
{
this.setLayout(new BorderLayout());
if (client_ == null)
{
client_ = cefApp_.createClient();
}
//添加js交互
jsActive(client_);
browser_ = client_.createBrowser(startURL, OS.isLinux(), false);
browerUI_ = browser_.getUIComponent();
this.add(browerUI_, BorderLayout.CENTER);
this.setSize(size);
this.setPreferredSize(size);
}
/**
* 设置浏览器新的URL地址
*
* @param url
*/
public void setUrl(String url)
{
if(browser_ != null)
{
browser_.loadURL(url);
}
}
// 关闭程序之前必须调用这个
public void disposeApp()
{
cefApp_.dispose();
}
public CefApp getCefApp_()
{
return cefApp_;
}
public CefClient getClient_()
{
return client_;
}
public CefBrowser getBrowser_()
{
return browser_;
}
public Component getBrowerUI_()
{
return browerUI_;
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String url = "http://www.baidu.com";
ChromePanel chromePanel = new ChromePanel(url);
frame.setSize(chromePanel.getPreferredSize());
frame.setContentPane(chromePanel);
frame.setVisible(true);
}
}
部署jcef相关资源到jre
a.解压linux64.zip资源;
b.复制java-cef-build-bin/bin/lib/linux64的所有文件到jre/lib和jre/lib/amd64目录
c.然后执行指令chmod +x -R jre/
运行的时候有个小注意事项,设置java.library.path为jdk目录的jre/lib,防止cef找不到依赖
-Djava.library.path=JDK所在目录/jre/lib
示例:-Djava.library.path=/root/soft/jdk1.8.0_241/jre/lib
运行效果如下,用了three.js的demo,运行WebGL效果正常: