我只想和你们分享我们的j2objc设置,因为我们花了一些时间在我们的一个项目中对其进行微调。我们目前正在使用400+编译j2objc文件,包中有类名副本,必须能够在xcode中调试java代码,这样我们就可以直接放置断点并通过java代码执行步骤(而不是objc)。我们为改进构建时间所做的最后一次调整节省了我们在CI上构建时间的50%,这与最初(官方建议的)方法相比是一个很大的帮助。
发布于 2018-02-13 20:19:50
我们正在一个单独的框架中构建我们的j2objc部件,这是我们正在使用的java库的一部分。要点是使用不同的方法将java转换为objC,而不是使用构建规则,而是使用“运行脚本”构建阶段。请注意,我们确实需要能够调试xcode中的java代码,因此j2objc团队也建议的外部目标方法对我们无效,构建规则方法确实使我们慢了下来。
我们在编译源代码阶段之前添加了构建阶段:
"${PROJECT_DIR}/scripts/j2objc.sh" "${PROJECT_DIR}" "${J2OBJC_HOME}" "${JAVA_SOURCE}";j2objc.sh:
#!/bin/sh
if [ -z ${1} ]; then
echo "error: PROJECT_DIR is not set."
exit 1;
fi;
if [ -z ${2} ]; then
echo "error: J2OBJC_HOME is not set."
exit 1;
fi;
if [ -z ${3} ]; then
echo "error: JAVA_SOURCE is not set."
exit 1;
fi;
PROJECT_DIR=$1
J2OBJC_HOME=$2
JAVA_SOURCE=$3
if [ ! -f "${J2OBJC_HOME}/j2objc" ]; then
echo "J2OBJC_HOME is not correctly defined, currently set to '${J2OBJC_HOME}'";
exit 1;
fi;
SHOULD_COMPILE=$(find "${JAVA_SOURCE}" -name '*.java' | {
while read filename; do
JAVA_PATH="${filename}";
JAVA_RELATIVE_PATH=$(sed -e "s|^$JAVA_SOURCE||" <<< "${JAVA_PATH}");
BASE_RELATIVE_PATH=$(sed -e "s|.java$||" <<< "${JAVA_RELATIVE_PATH}");
BASE_ABSOLUTE_PATH="${JAVA_SOURCE}/${BASE_RELATIVE_PATH}";
H_PATH="${BASE_ABSOLUTE_PATH}.h";
M_PATH="${BASE_ABSOLUTE_PATH}.m";
if [ ! -f "${H_PATH}" ] || [ ! -f "${M_PATH}" ] || [ "${H_PATH}" -ot "${JAVA_PATH}" ] || [ "${M_PATH}" -ot "${JAVA_PATH}" ]; then
echo "1";
break;
fi;
done
}
)
if [ "$SHOULD_COMPILE" = "1" ]; then
"${J2OBJC_HOME}/j2objc" \
-d "${JAVA_SOURCE}" \
-sourcepath "${JAVA_SOURCE}" \
-classpath "${J2OBJC_HOME}/lib/jsr305-3.0.0.jar" \
--swift-friendly \
--strip-reflection \
--no-segmented-headers \
-use-arc \
--static-accessor-methods \
--nullability \
--prefixes "${PROJECT_DIR}/prefixes.properties" \
-g \
`find "${JAVA_SOURCE}" -name '*.java'`;
fi;您仍然需要将正式描述的构建规则留在您的项目中,只需从其中删除脚本,以便它只列出输出文件。
我们的样子是这样的:
$(INPUT_FILE_DIR)/${INPUT_FILE_BASE}.h
$(INPUT_FILE_DIR)/${INPUT_FILE_BASE}.m实际上,使用这种方法实现的是更快的j2objc转换,因为您没有为每个文件执行单独的j2objc实例来翻译,而是告诉一个j2objc实例一次翻译所有的java文件,最后,您只需使用构建规则告诉xcode翻译的文件在哪里,这样就可以编译它们。您应该只将java文件添加到项目中,而不是objC文件,它们将根据构建规则进行编译。
我们使用脚本自动将objC文件导入到框架中,它也是在构建阶段定义的,并且必须在编译源代码构建阶段之后定义:
#!/bin/sh
PROJ_HEADER="${PROJECT_DIR}/Proj.h";
PROJ_TMP_HEADER="${PROJECT_DIR}/Proj.h.tmp";
HEADERS_PATH="${PROJECT_DIR}/../src/main/java/";
cat /dev/null > "${PROJ_TMP_HEADER}";
echo "// Generated by Proj external build target
#ifndef proj_h
#define proj_h
#import \"Proj/Bridge.h\"
" >> "${PROJ_TMP_HEADER}";
find "${PROJECT_DIR}/../src/main/java" -type f -name '*.h' | sed -e "s|^$HEADERS_PATH||" | sort | awk '{print "#import \"" $0 "\""}' >> "${PROJ_TMP_HEADER}";
echo "
#endif" >> "${PROJ_TMP_HEADER}";
FILE1=`cat "${PROJ_HEADER}" 2>/dev/null`;
FILE2=`cat "${PROJ_TMP_HEADER}"`;
if [ "$FILE1" = "$FILE2" ]; then
rm -f "${PROJ_TMP_HEADER}";
else
mv "${PROJ_TMP_HEADER}" "${PROJ_HEADER}";
fi;最后的逻辑是这样,所以我们不会在每个构建中更新标头,因为整个项目需要重新编译。
正如您可能已经注意到的,我们将objC文件存储在java文件旁边,以使构建规则可以编写,因为xcode不支持在输出文件中使用一些更复杂的宏,但这并不理想,因此我们想出了一个简单的解决方案,以便在需要时更容易地从目录中删除所有objc文件(例如,由于库中的某些更改,我们需要将java文件重新添加到项目中)。
解决方案是在清理项目时删除objc文件。您只需要创建一个新的外部构建目标,因为这是在清理项目时执行某些操作的唯一方法。它在xcode 9中被命名为“外部构建系统”。
这就是它的样子:
#! /bin/sh
if [ "${ACTION}" == "clean" ]
then
rm -f "${PROJECT_DIR}/Proj.h"
find "${PROJECT_DIR}/../src/main" -type f -name '*.h' -delete
find "${PROJECT_DIR}/../src/main" -type f -name '*.m' -delete
fi然后,您需要将干净的目标添加到j2objc框架的依赖项中,以便它在构建和清理时实际运行。
发布于 2018-12-19 16:11:27
我们使用了和你相似的方法。然而,在我看来,目前我们正在更好地利用:
当*.java更改时,这种方法具有自动生成*.m的巨大优势--代码竞争不需要在xCode中重新编译项目。对于XCode,我们只处理另一个.m文件,不需要使用脚本等等,根据我们的经验,xCode处理这个问题更好。我们只认为只要添加新的*.java文件或做一些重构,就必须运行pod。我们正在试验自动调用pod安装,但目前我们是手动调用它。
我们还实现了协议缓冲区的自动编译,因为我们在项目中也需要它们。
该工具可在npmjs - https://www.npmjs.com/package/j2objcworker上使用。
https://stackoverflow.com/questions/48774972
复制相似问题