Posting this for the benefit of others who are trying to make java CEF work in Mac App sandbox, and Mac AppStore. There are some key elements to success:
1. The "Chromium Embedded Framework.framework" has a file structure that isn't "valid". It needs to be fixed. You can read about the structure at
https://developer.apple.com/library/arc ... atomy.html. Here is a snippet from my codesigning script that shows how I transform the framework to a valid structure:
- Code: Select all
CEF_FRAMEWORK="$APP_PATH/Frameworks/Chromium Embedded Framework.framework"
if [ -d "$CEF_FRAMEWORK" ] && [ ! -d "$CEF_FRAMEWORK/Versions" ]; then
# The Chromium Embedded Framework comes malformed so Apple won't accept it.
# We need to fix it to be a valid format
echo "Fixing structure of $CEF_FRAMEWORK so that Apple doesn't complain"
mv "$CEF_FRAMEWORK" "${CEF_FRAMEWORK}-tmp"
mkdir "$CEF_FRAMEWORK"
mkdir "$CEF_FRAMEWORK/Versions"
mv "${CEF_FRAMEWORK}-tmp" "$CEF_FRAMEWORK/Versions/A"
CURR_DIRECTORY=`pwd`
cd "$CEF_FRAMEWORK/Versions"
ln -s A Current
cd ..
ln -s Versions/Current/Resources Resources
ln -s Versions/Current/Libraries Libraries
ln -s Versions/Current/"Chromium Embedded Framework" "Chromium Embedded Framework"
cd "$CURR_DIRECTORY"
fi
TIP: It is important, when creating the symlinks in the above script that you DO NOT have a trailing slash in symlink paths. Otherwise codesigning will fail.2. You
MUST include the "com.apple.security.application-groups" entitlement. The name of this application group
MUST start with your developer Team ID. Your team ID is easy to find in iTunes connect, or even just looking at your development certificate name. It is the code that is in the parenthesis at the end of your signing identity name. E.g. "Mac 3rd Party Developer XXXX (QYLULX7)". In this example it would be "QYLULX7".
3. You
MUST change the CFBundleIdentifier of the "jcef Helper" applications so that they start with your the app group ID that you chose in step 2. This is because CEF uses mach ports to communicate and sets the service ID for these ports to a name that begins with the bundle ID. But the Mac app sandbox will only allow these apps to connect to these ports if their service name begins with a group name that is listed in the app-groups entitlement. Hence the bundle ID of the helper app needs to match the app group.
Here is a snippet from my codesigning script that handles the changing of these bundle IDs:
- Code: Select all
if [ ! -z "$CN1_BUNDLE_IDENTIFIER" ]; then
find "$APP_PATH"/Frameworks -name Info.plist -exec plutil -replace CFBundleIdentifier -string "$CN1_BUNDLE_IDENTIFIER" {} \;
fi
In the above example the $CN1_BUNDLE_IDENTIFIER is the bundle identifier I chose for the helper applications. This needs to start with the team ID and should match the app-group you've entered in your entitlements. The $APP_PATH is the path do your app bundle's Contents directory, and assumes that you have placed the helper apps (and the Chromium Embedded Framework.framework inside your MyApp.app/Contents/Frameworks directory.
4. In your java app, you must set the --framework-dir-path, --main-bundle-path, and --browser-subprocess-path arguments in the CefApp.startup(args) call. Here is a snippet from my java app as an example:
- Code: Select all
private static String[] createArgs() {
List<String> args = new ArrayList<String>();
if (isMac) {
if (!"true".equals(System.getProperty("cn1.cef.bundled"))) {
// The cn1.cef.bundled flag is set in SEWrapper to indicate that CEF is bundled in the .app
// Otherwise it needs to get CEF from the central location specified
args.add(String.format("--framework-dir-path=%s/Chromium Embedded Framework.framework", getLibPath()));
args.add(String.format("--main-bundle-path=%s/jcef Helper.app", getLibPath()));
args.add(String.format("--browser-subprocess-path=%s/jcef Helper.app/Contents/MacOS/jcef Helper", getLibPath()));
}
args.add("--disable-gpu");
} else if (isWindows) {
// no extra stuff here
//args.add(String.format("--browser-subprocess-path=%s\\jcef_helper.exer", getLibPath()));
args.add("--disable-gpu");
args.add("--disable-software-rasterizer");
args.add("--disable-gpu-compositing");
} else if (isUnix) {
// no extra stuff here
//args.add(String.format("--browser-subprocess-path=%s\\jcef_helper.exer", getLibPath()));
args.add("--disable-gpu");
args.add("--disable-software-rasterizer");
args.add("--disable-gpu-compositing");
} else {
throw new UnsupportedOperationException("CEF Not implemented on this platform yet");
}
//args.add("--allow-file-access-from-files");
args.add("--touch-events=enabled");
args.add("--enable-media-stream");
//args.add("--device-scale-factor=4");
//args.add("--force-device-scale-factor=4");
args.add("--autoplay-policy=no-user-gesture-required");
args.add("--enable-usermedia-screen-capturing");
//System.out.println("CEF Args: "+args);
return args.toArray(new String[args.size()]);
}
private static String getLibPath() {
return System.getProperty("cef.libPath", null);
}
Notice that this relies on the "cef.libPath" system property to pass in the path to the Frameworks directory. I set this in the Info.plist file for my main app bundle. The following is the Info.plist file from sample app so you can see how that system property is set.
- Code: Select all
<?xml version="1.0" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>BasicBrowserComponentSample</string>
<key>CFBundleIconFile</key>
<string>icon.icns</string>
<key>CFBundleIdentifier</key>
<string>com.codename1.samples.BasicBrowserComponentSample</string>
<key>CFBundleDisplayName</key>
<string>BasicBrowserComponentSample</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>BasicBrowserComponentSample</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0.49</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) 2021 CodenameOne</string>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.business</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>JVMRuntime</key>
<string>jre</string>
<key>JVMMainClassName</key>
<string>com.codename1.samples.BasicBrowserComponentSampleStub</string>
<key>CFBundleDocumentTypes</key>
<array>
</array>
<key>LSArchitecturePriority</key>
<array>
<string>x86_64</string>
</array>
<key>LSEnvironment</key>
<dict>
<key>LC_CTYPE</key>
<string>UTF-8</string>
</dict>
<key>JVMOptions</key>
<array>
<string>-Xdock:name=BasicBrowserComponentSample</string>
<string>-Dapple.laf.useScreenMenuBar=true</string>
<string>-Dcom.apple.macos.use-file-dialog-packages=true</string>
<string>-Dcom.apple.macos.useScreenMenuBar=true</string>
<string>-Dcom.apple.mrj.application.apple.menu.about.name=BasicBrowserComponentSample</string>
<string>-Dcom.apple.smallTabs=true</string>
<string>-Dfile.encoding=UTF-8</string>
<string>-Djava.library.path=$APP_ROOT/Contents/Java/:$APP_ROOT/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries</string>
<string>-Dcef.libPath=$APP_ROOT/Contents/Frameworks</string>
<string>-Xmx1024M</string>
</array>
<key>JVMArguments</key>
<array>
</array>
</dict>
</plist>