在鸿蒙 PC 上尝试运行 Redis(2):调试、打包和发布
这次折腾花的时间比编译还多。编译虽然遇到各种兼容性问题,但至少知道问题在哪,怎么解决。打包和签名这块,很多问题都是隐式的,不试不知道。不过现在至少能打包出正确的 APP 文件了,也算是个进步。如果后续在真机上测试有问题,我再写第三篇。代码和脚本都在 GitHub 上,虽然还有很多不完善的地方,但至少能用了。如果有人也想在鸿蒙 PC 上打包应用,可以参考一下。当然,如果遇到问题,欢迎提 Issue。
上一篇写了怎么把 Redis 编译成 HNP 包,这次说说后面踩的坑。说实话,我以为编译完就差不多了,结果打包和签名这块把我折腾得够呛。
从 HNP 到 HAP:我以为很简单
编译出 redis.hnp 后,我以为接下来就是打包成 HAP,然后就能在鸿蒙 PC 上跑了。事实证明我想多了。
鸿蒙的应用打包流程是这样的:HNP → HAP → APP。HNP 是原生包,HAP 是应用包,APP 是最终的上架包。每一步都有坑等着你。
第一个坑:HAP 打包参数
我一开始直接用 app_packing_tool 打包 HAP,结果报错说找不到 module.json。我:???这啥玩意儿?
查了半天才知道,HAP 打包需要一堆中间文件:
module.json- 模块配置pack.info- 打包信息resources.index- 资源索引- 还有一堆其他的
这些文件都是 DevEco Studio 构建项目时自动生成的。我一开始想手动创建,结果格式不对,打包一直失败。
后来我干脆在 DevEco Studio 里创建了一个空的鸿蒙项目,然后把 HNP 文件放进去,让 DevEco Studio 帮我生成这些文件。虽然有点绕,但至少能用了。
签名:最让人抓狂的部分
HAP 打包成功后,我以为就完事了。结果上传到 App Gallery Connect 的时候,提示错误码 991:非法软件包。
我:???啥意思?
查了一下,错误码 991 表示软件包未签名。我这才意识到,HAP 文件需要签名才能上架。
第一次尝试:直接用 app_packing_tool 签名
我看了文档,发现 app_packing_tool 的 hap 模式不支持签名参数。文档里说:
HAP 模式不支持签名参数,需要在打包后单独签名
行吧,那就单独签名。我找到了 hap-sign-tool.jar,开始研究怎么用。
签名参数:一堆乱七八糟的东西
hap-sign-tool 需要的参数有:
keystoreFile- 密钥库文件keystorePwd- 密钥库密码keyAlias- 密钥别名keyPwd- 密钥密码appCertFile- 应用证书profileFile- 配置文件signAlg- 签名算法compatibleVersion- 兼容版本
这些信息都在 build-profile.json5 里,但格式是 JSON5(支持注释和尾随逗号)。我一开始用 Python 的 json 模块解析,结果报错说格式不对。
我:???JSON5 不是 JSON 吗?
查了一下才知道,JSON5 是 JSON 的超集,标准 JSON 解析器不支持。我只好用 grep 和 sed 硬提取,但这样很容易出错。
后来我写了个 Node.js 脚本,用 json5 包来解析,这才搞定。
密码加密:又一个坑
从 build-profile.json5 提取出密码后,我发现密码是加密的(以 000000 开头)。我直接拿这个加密密码去签名,结果报错:
ERROR: 11014003 Init keystore failed Error Message: keystore password was incorrect
我:???密码不对?
查了半天才知道,DevEco Studio 会把密码加密存储,但 hap-sign-tool 需要明文密码。我当时就懵了,这怎么搞?
最后我只好让用户通过环境变量提供明文密码:
export HAP_STORE_PASSWORD='你的明文密码'
export HAP_KEY_PASSWORD='你的明文密码'
虽然不太优雅,但至少能用了。如果用户不知道明文密码,就只能用 DevEco Studio 构建,或者手动签名。
compatibleVersion:差点把我搞崩溃
签名的时候还遇到一个问题:compatibleVersion 参数不能为空。
我一开始从 module.json 里提取 minCompatibleVersionCode,结果发现这个字段可能不存在。我又尝试从 minAPIVersion 提取,但 minAPIVersion 的格式是 60001021(6.0.1(21)),需要提取主要版本号。
我一开始用正则表达式提取,结果提取错了。最后用 cut -c1 提取第一位数字,这才搞定。
就这么一个小问题,我折腾了大半天。有时候真的觉得,这些工具的设计能不能再友好一点?
APP 打包:我以为很简单
HAP 签名成功后,我以为 APP 打包就简单了。结果又踩了坑。用 app_packing_tool 打包 APP 后,发现 APP 文件里包含了 redis.cer 和 redis.p7b 文件。我:???这啥玩意儿?
查了一下才知道,我在打包 APP 的时候传了 --signature-path 和 --certificate-path 参数,结果这些文件被直接打包进 APP 了,而不是用于签名。然后感觉又无解了,不签名如何上架呢?
最终解决方案
问了一下群友,发现有一种非常hack的方法可以让DevEco Studio正常打包带 hnp 的 hvigor 项目:就是直接修改 hvigor-ohos-plugin 的源码!具体修改方式如下:
修改 DevEco Studio\tools\hvigor\hvigor-ohos-plugin\src\builder\inner-java-command-builder\packing-tool-options.js
在文件最下面,添加 addHnpPath(t) 函数:
addHnpPath(t) {
return this.addFieldAndPath("--hnp-path", t);
}
force(t) {
return (
this.commandList.push("--force"),
this.commandList.push(t.toString()),
this
);
}
修改 DevEco Studio\tools\hvigor\hvigor-ohos-plugin\src\tasks\base\base-pack-hap-task.js
在 generateCommand 函数中填下以下代码:
let hnpPath = path_1.default.resolve(process.cwd(), "hnp");
if (fse.existsSync(hnpPath)) {
a.addHnpPath(hnpPath);
}
修改后 generateCommand 函数如下(由于代码仓限制脚本内个别变量名有所修改):
generateCommand(e, t) {
var s, o;
const a = new packing_tool_options_js_1.PackingToolOptions();
a.addCalledJarFile(this.sdkInfo.getPackageTool()),
a .addMode(this.mode)
.force(!0)
.addLibPath(this.libPath)
.addJsonPath(this.packageHapJsonPath)
.addResourcesPath(this.priorResourcePath || this.resourcePath)
.addIndexPath(this.indexPath)
.addPackInfoPath(e)
.addOutPath(t);
let hnpPath = path_1.default.resolve(process.cwd(), "hnp");
if (fse.existsSync(hnpPath)) {
a.addHnpPath(hnpPath);
}
const i =
hvigor_config_loader_1.HvigorConfigLoader.getInstance().getPropertiesConfigValue(
common_const_js_1.HvigorConfigConst.OHOS_PACK_COMPRESS_LEVEL
);
return (
i &&
fse.existsSync(
path_1.default.resolve(this.pathInfo.getModulePath(), "libs")
) &&
a.addCompressLevel(i, this.sdkInfo.getSdkVersion()),
this.targetService.getAnBuildMode() &&
(fse.existsSync(this.anBuildOutputPath) &&
a.addAnPath(this.anBuildOutputPath),
fse.existsSync(this.apDirPath) && a.addDirList([this.apDirPath])),
fse.existsSync(this.rpcidSc) && a.addSysCapPath(this.rpcidSc),
fse.existsSync(this.jsAssetsPath) && a.addJsPath(this.jsAssetsPath),
fse.existsSync(this.etsAssetsPath) && a.addEtsPath(this.etsAssetsPath),
fse.existsSync(this.nodeModulesPath) &&
a.addDirList([this.nodeModulesPath]),
fse.existsSync(this.pkgContextInfoPath) &&
(null ===
(o =
null === (s = this.targetService.getBuildOption()) || void 0 === s
? void 0
: s.strictMode) || void 0 === o
? void 0
: o.useNormalizedOHMUrl) &&
a.addPkgContextInfoPath(this.pkgContextInfoPath),
a.build()
);
}
修改后重启DevEco然后打包即可。
原帖地址:https://developer.huawei.com/consumer/cn/forum/topic/0202196674965008231
最后
这次折腾花的时间比编译还多。编译虽然遇到各种兼容性问题,但至少知道问题在哪,怎么解决。打包和签名这块,很多问题都是隐式的,不试不知道。
不过现在至少能打包出正确的 APP 文件了,也算是个进步。如果后续在真机上测试有问题,我再写第三篇。
代码和脚本都在 GitHub 上,虽然还有很多不完善的地方,但至少能用了。如果有人也想在鸿蒙 PC 上打包应用,可以参考一下。
当然,如果遇到问题,欢迎提 Issue。如果觉得哪里可以改进,也欢迎提 PR。
项目地址:https://github.com/ohosvscode/redis
如果这篇文章对你有帮助,或者你也踩过类似的坑,欢迎在评论区聊聊。
更多推荐





所有评论(0)