Open GoogleCodeExporter opened 9 years ago
Hi th...,
that's a thing which is on my list for longer time, too. Maybe I'll create a
patch within the next weeks/month.
One thing you've to mention is the required application layout of CEF
(https://code.google.com/p/chromiumembedded/wiki/GeneralUsage#Application_Layout
). Especially for Mac it isn't that easy going.
Regards, Kai
Original comment by k...@censhare.de
on 6 Nov 2014 at 6:45
Hi Kai,
I'm glad to hear this already is on your list. My customer is currently
thinking about replacing his Swing-GUIs with HTML-GUIs that need to run in the
old application Frame. Since the Java FX Web View has an awful JavaScript
Performance the JCEF seems to be the only way to realize this.
Regards, Thies
Original comment by th...@literarisch-wertvoll.de
on 7 Nov 2014 at 9:11
I had to do this for our app embedding JCEF. This is something other libraries
such as SWT and JOGL do as well. In our app, we extract to a temp folder, whose
location is persisted by the application. We have a cb-win64.jar, cb-win32.jar,
cb-macosx64.jar with all the appropriate resources.
Here's that code below. You'll probably come up with something optimized for
your build scripts. A few interesting notes:
1. Notice the Mac is a bit special. There's also a list of resources that need
the executable bit to be set.
2. The temp folder must be a location with full privileges on Windows. I'm
saying this because we're using Javawebstart and some of its api's were
pointing to a Windows folder with lower permissions (LocalLow folder, can't
link to dll's outside of this folder, so could not link to jawt.dll).
The app calls extractToLibraryPath on startup. Then it can assumes the jcef/cef
libraries are available to be loaded.
I also used System.loadLibrary with absolute paths instead of relative paths as
JCEF currently does today. This way, we don't need to rely on external
properties, we just need to know where we extracted the libs.
If this doesn't help, please ignore this comment... It's working well for us.
AutoExtract.java
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.cef.OS;
/**
* Automatically extract the native files in the appropriate structure.
* This assumes the native files are properly packaged into the correct platform jar.
*/
public class AutoExtract {
static String[] resourcesWin64 = new String[] { "version.txt", "cef.pak",
"d3dcompiler_43.dll", "d3dcompiler_46.dll",
"devtools_resources.pak", "ffmpegsumo.dll", "icudtl.dat",
"jcef.dll", "jcef_helper.exe", "libcef.dll", "libEGL.dll",
"libGLESv2.dll",
"locales/en-US.pak"
};
static String[] resourcesWin32 = resourcesWin64;
static String[] executablesMacOS64 = new String[] {
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/ffmpegsumo.so",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_inspector",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_report_sender.app/Contents/MacOS/crash_report_sender",
"jcef_app.app/Contents/Frameworks/jcef Helper EH.app/Contents/MacOS/jcef Helper EH",
"jcef_app.app/Contents/Frameworks/jcef Helper NP.app/Contents/MacOS/jcef Helper NP",
"jcef_app.app/Contents/Frameworks/jcef Helper.app/Contents/MacOS/jcef Helper",
"jcef_app.app/Contents/Frameworks/libplugin_carbon_interpose.dylib",
"jcef_app.app/Contents/Java/libjcef.dylib"
};
static String[] resourcesMacOS64 = new String[] {
"version.txt",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/ffmpegsumo.so",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/am.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ar.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/bg.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/bn.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ca.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/cef.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_inspector",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_report_sender.app/Contents/Info.plist",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_report_sender.app/Contents/MacOS/crash_report_sender",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_report_sender.app/Contents/PkgInfo",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_report_sender.app/Contents/Resources/Breakpad.nib",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_report_sender.app/Contents/Resources/crash_report_sender.icns",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/crash_report_sender.app/Contents/Resources/English.lproj/Localizable.strings",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/cs.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/da.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/de.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/devtools_resources.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/el.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/en.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/en_GB.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/es.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/es_419.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/et.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/fa.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/fi.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/fil.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/fr.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/gu.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/he.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/hi.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/hr.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/hu.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/id.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/Info.plist",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/it.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ja.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/kn.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ko.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/lt.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/lv.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ml.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/mr.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ms.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/nb.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/nl.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/pl.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/pt_BR.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/pt_PT.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ro.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ru.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/sk.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/sl.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/sr.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/sv.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/sw.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/ta.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/te.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/th.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/tr.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/uk.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/vi.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/zh_CN.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/Chromium Embedded Framework.framework/Resources/zh_TW.lproj/locale.pak",
"jcef_app.app/Contents/Frameworks/jcef Helper EH.app/Contents/Info.plist",
"jcef_app.app/Contents/Frameworks/jcef Helper EH.app/Contents/MacOS/jcef Helper EH",
"jcef_app.app/Contents/Frameworks/jcef Helper EH.app/Contents/PkgInfo",
"jcef_app.app/Contents/Frameworks/jcef Helper NP.app/Contents/Info.plist",
"jcef_app.app/Contents/Frameworks/jcef Helper NP.app/Contents/MacOS/jcef Helper NP",
"jcef_app.app/Contents/Frameworks/jcef Helper NP.app/Contents/PkgInfo",
"jcef_app.app/Contents/Frameworks/jcef Helper.app/Contents/Info.plist",
"jcef_app.app/Contents/Frameworks/jcef Helper.app/Contents/MacOS/jcef Helper",
"jcef_app.app/Contents/Frameworks/jcef Helper.app/Contents/PkgInfo",
"jcef_app.app/Contents/Frameworks/libplugin_carbon_interpose.dylib",
"jcef_app.app/Contents/Info.plist",
"jcef_app.app/Contents/Java/libjcef.dylib",
"jcef_app.app/Contents/PkgInfo"
};
static final String archWin64 = "win64";
static final String archWin32 = "win32";
static final String archMacOSX64 = "macosx64";
Path rootDir;
public AutoExtract() {
}
public static class LibraryPathData {
public String libraryPath;
public String arch;
public String libraryPathWithArch;
public boolean success;
public boolean reusedCache;
public Exception error;
}
/**
* Create a native library cache under the given root folder if none is found under
* the current architecture.
* <p>
* Returns information about the cache location, architecture, success and if an existing cache
* was reused or a new one created.
*/
public LibraryPathData extractToLibraryPath(String libraryPath) {
if (libraryPath == null)
throw new IllegalArgumentException("Must provide native library path");
LibraryPathData result = new LibraryPathData();
try {
String arch = getArchFolderName();
rootDir = new File(libraryPath).toPath();
Path archPath = new File(rootDir.toAbsolutePath().toFile(), arch).toPath();
boolean exists = Files.exists(archPath);
result.reusedCache = !exists;
result.libraryPath = libraryPath;
result.arch = arch;
result.libraryPathWithArch = archPath.toAbsolutePath().toString();
if (!exists) {
Path rootFolder = Files.createDirectory(archPath);
String rootFolderString = rootFolder.toAbsolutePath().toString();
extract(arch, rootFolderString);
}
result.success = true;
return result;
} catch (IOException e) {
result.success = false;
result.error = e;
e.printStackTrace();
}
return result;
}
/*
* processes the existing version.txt file in the specified library path
*/
public static String getExistingVersion(String libraryPath) {
String arch = getArchFolderName();
Path nativeVersionPath = new File(libraryPath, arch+ "//version.txt").toPath();
if(!Files.exists(nativeVersionPath, LinkOption.NOFOLLOW_LINKS)) {
return null;
}
byte[] encoded = null;
try {
encoded = Files.readAllBytes(Paths.get(nativeVersionPath.toUri()));
} catch (IOException e) {
e.printStackTrace();
return null;
}
String version = null;
if(encoded != null) {
version = new String(encoded, Charset.defaultCharset());
}
return version;
}
/*
* Retrieves the version from "version.txt" in the jar
* @return
*/
public static String getPackagedNativeVersion() {
ClassLoader loader = AutoExtract.class.getClassLoader();
InputStream is = loader.getResourceAsStream("version.txt");
if(is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder out = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
out.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return out.toString();
}
System.out.println("Could not find a packaged version file");
return null;
}
/**
* Return the name of the arch specific subfolder we extract the native libraries into
*/
public static String getArchFolderName() {
String arch = null;
if (isWindows())
arch = isWindows32Bit() ? archWin32 : archWin64;
if (isMac())
arch = archMacOSX64;
if (arch == null)
throw new RuntimeException("Unsupported platform: "+System.getProperty("os.name"));
return arch;
}
/**
* Extract native files to a temp folder.
* Returns the root of that folder.
*
* The folder and all its contents get deleted when program exits.
*/
public String extractToTempDirectory() {
try {
String arch = null;
if (isWindows())
arch = isWindows32Bit() ? archWin32 : archWin64;
if (isMac())
arch = archMacOSX64;
if (arch == null)
throw new RuntimeException("Unsupported platform: "+System.getProperty("os.name"));
rootDir = Files.createTempDirectory("cef"+Long.toString(System.nanoTime()));
Path rootFolder = Files.createDirectory(new File(rootDir.toAbsolutePath().toFile(), arch).toPath());
String rootFolderString = rootFolder.toAbsolutePath().toString();
extract(arch, rootFolderString);
return rootFolderString;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().startsWith("windows");
}
public static boolean isWindows32Bit() {
return "x86".equals(System.getProperty("os.arch"));
}
public static boolean isMac() {
return System.getProperty("os.name").toLowerCase().startsWith("mac");
}
/**
* Extract the given resources under the given install path from the given
* jar name. Resources are String using / as a folder separator if they are
* under a subfolder. Subfolder gets created as needed.
*/
void extract(String arch, String installPath) throws IOException {
String[] resources = null;
File rootFolder = new File(installPath);
if (archWin64.equals(arch)) {
resources = resourcesWin64;
}
if (archWin32.equals(arch)) {
resources = resourcesWin32;
}
if (archMacOSX64.equals(arch)) {
resources = resourcesMacOS64;
}
ClassLoader loader = AutoExtract.class.getClassLoader();
List<String> executables = OS.isMacintosh() ? Arrays.asList(executablesMacOS64) : new ArrayList<String>();
for (String resource : resources) {
File target = new File(rootFolder, resource);
Path path = target.getAbsoluteFile().toPath();
System.out.println("Extracting "+path);
Path parent = path.getParent();
Files.createDirectories(parent);
InputStream in = loader.getResourceAsStream(resource);
Files.copy(in, path);
if (executables.contains(resource)) {
target.setExecutable(true);
}
}
}
public void deleteTempDirectoryOnShutdown() {
try {
Files.walkFileTree(rootDir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
throw e;
}
} );
} catch (IOException e) {
throw new RuntimeException("Failed to delete "+rootDir, e);
}
}
/**
* Utility to generate the list of mac resources to extract from the jar and mark as executable.
*/
public static void main(String[] args) {
String jcefAppRootFolder = "/Users/admin/Documents/chrix/data/git/embeddedBrowserR60/cef/native/macosx64/jcef_app.app";
String rootFilter = "/Users/admin/Documents/chrix/data/git/embeddedBrowserR60/cef/native/macosx64/";
List<String> files = new ArrayList<String>();
List<String> executableFiles = new ArrayList<String>();
scanFiles(jcefAppRootFolder, files, executableFiles);
System.out.println("-- Files --");
for (String entry : files) {
System.out.println("\""+entry.substring(rootFilter.length())+"\",");
}
System.out.println("-- Executables --");
for (String entry : executableFiles) {
System.out.println("\""+entry.substring(rootFilter.length())+"\",");
}
}
/**
* Given the root directory, scan all children recursively. Return all files found. Files requiring the executable bit are also collected in an extra list.
*/
static void scanFiles(String directory, List<String> files, List<String> executableFiles) {
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get(directory))) {
for (Path path : ds) {
if (Files.isDirectory(path)) {
scanFiles(path.toString(), files, executableFiles);
}
if (Files.isRegularFile(path)) {
files.add(path.toString());
if (Files.isExecutable(path)) {
executableFiles.add(path.toString());
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Original comment by christop...@gmail.com
on 10 Nov 2014 at 8:51
Original issue reported on code.google.com by
th...@literarisch-wertvoll.de
on 5 Nov 2014 at 3:12