HarmonyOS 5开发从入门到精通(二十):应用发布与上架
HarmonyOS 5开发从入门到精通(二十):应用发布与上架
本章将完整介绍HarmonyOS应用从打包签名到上架应用市场的全流程,帮助开发者顺利完成应用发布。
一、核心概念
1. 应用签名机制
HarmonyOS通过数字证书(.cer文件)和Profile文件(.p7b文件)等签名信息来保证应用的完整性。应用上架到华为应用市场必须通过签名校验,这是应用安全分发的基础保障。
2. 应用分发流程
HarmonyOS应用的分发遵循严格的审核和发布流程,包括应用信息配置、软件包上传、审核提交、版本管理等环节,确保应用符合华为应用市场的质量标准。
二、关键API详解
1. 构建配置API
// build-profile.json5配置示例
{
"app": {
"signingConfigs": [
{
"name": "release",
"material": {
"certpath": "signing/release.cer",
"storePassword": "yourpassword",
"keyAlias": "release",
"keyPassword": "yourpassword",
"profile": "signing/release.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "signing/release.p12"
}
}
]
}
}
2. 发布前检查API
import bundleManager from '@ohos.bundle.bundleManager';
import permission from '@ohos.permission';
class AppPublishChecker {
// 检查权限声明
static async checkRequiredPermissions(): Promise<string[]> {
const requiredPerms = [
permission.Permission.INTERNET,
permission.Permission.READ_MEDIA
];
const missingPerms: string[] = [];
const bundleInfo = await bundleManager.getBundleInfoForSelf();
for (const perm of requiredPerms) {
if (!bundleInfo.reqPermissions.includes(perm)) {
missingPerms.push(perm);
}
}
return missingPerms;
}
}
3. 自动化构建API
// 终端构建命令
./gradlew assembleRelease
// 或者使用图形界面
// Build > Build HAP(s)/APP(s) > Build Release HAP
4. 包体规范检查
// 包体大小限制检查
class PackageSizeChecker {
static readonly MAX_APP_SIZE = 2 * 1024 * 1024 * 1024; // 2GB
static readonly MAX_HAP_SIZE = 20 * 1024 * 1024; // 20MB
static checkPackageSize(packagePath: string): boolean {
const stats = fs.statSync(packagePath);
return stats.size <= this.MAX_APP_SIZE;
}
}
三、实战案例
完整发布流程示例
import http from '@ohos.net.http';
import fs from '@ohos.file.fs';
// 应用发布管理器
class AppPublisher {
private static readonly AGC_API = 'https://connect-api.cloud.huawei.com';
// 一键发布流程
static async publishApp(appId: string, hapPath: string): Promise<boolean> {
try {
console.log('开始应用发布流程...');
// 1. 运行预检查
const precheck = await this.runPrePublishChecks(hapPath);
if (!precheck.passed) {
console.error('预检查未通过:', precheck.details);
return false;
}
// 2. 上传HAP文件
console.log('上传应用包文件中...');
const uploadResult = await this.uploadPackage(appId, hapPath);
// 3. 提交审核
console.log('提交应用审核...');
const reviewResult = await this.submitForReview(appId, uploadResult.versionId);
console.log('应用发布流程完成,跟踪ID:', reviewResult.trackingId);
return true;
} catch (error) {
console.error('发布流程出错:', error);
return false;
}
}
// 发布前检查
private static async runPrePublishChecks(hapPath: string): Promise<any> {
const checks = {
packageSize: PackageSizeChecker.checkPackageSize(hapPath),
permissions: await AppPublishChecker.checkRequiredPermissions(),
signature: await this.verifySignature(hapPath)
};
return {
passed: checks.packageSize && checks.permissions.length === 0 && checks.signature,
details: checks
};
}
// 上传应用包
private static async uploadPackage(appId: string, hapPath: string): Promise<any> {
const token = await this.getAGCToken();
const httpRequest = http.createHttp();
try {
const file = await fs.open(hapPath, fs.OpenMode.READ_ONLY);
const fileStat = await fs.stat(hapPath);
const fileContent = await fs.read(file.fd, { length: fileStat.size });
await fs.close(file.fd);
const response = await httpRequest.request(
`${this.AGC_API}/api/v1/apps/${appId}/packages`,
{
method: 'POST',
header: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'multipart/form-data'
},
extraData: {
'file': {
filename: hapPath.split('/').pop(),
contentType: 'application/octet-stream',
data: fileContent
}
}
}
);
return JSON.parse(response.result);
} catch (error) {
throw new Error(`上传应用包失败: ${error}`);
}
}
}
// 发布状态监控组件
@Entry
@Component
struct PublishStatusMonitor {
@State appId: string = '';
@State trackingId: string = '';
@State status: string = 'pending';
@State lastUpdate: string = '';
private timer: number = 0;
onPageShow() {
const params = router.getParams();
if (params) {
this.appId = params.appId;
this.trackingId = params.trackingId;
this.startStatusPolling();
}
}
onPageHide() {
this.stopStatusPolling();
}
private startStatusPolling(): void {
this.timer = setInterval(() => {
this.checkStatus();
}, 300000); // 每5分钟检查一次
}
private stopStatusPolling(): void {
if (this.timer) {
clearInterval(this.timer);
}
}
private async checkStatus(): Promise<void> {
try {
const httpRequest = http.createHttp();
const token = await this.getAGCToken();
const response = await httpRequest.request(
`https://connect-api.cloud.huawei.com/api/v1/apps/${this.appId}/reviews/${this.trackingId}`,
{
method: 'GET',
header: {
'Authorization': `Bearer ${token}`
}
}
);
const result = JSON.parse(response.result);
this.status = result.status;
this.lastUpdate = new Date().toLocaleString();
} catch (error) {
console.error('获取审核状态失败:', error);
this.status = 'error';
}
}
build() {
Column({ space: 20 }) {
Text('应用审核状态')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text(`应用ID: ${this.appId}`)
.fontSize(16)
Text(`跟踪ID: ${this.trackingId}`)
.fontSize(16)
Divider()
if (this.status === 'pending') {
LoadingProgress()
Text('审核中,请耐心等待...')
.fontSize(16)
.fontColor(Color.Blue)
} else {
Text(`状态: ${this.getStatusText()}`)
.fontSize(20)
.fontColor(this.getStatusColor())
Text(`最后更新: ${this.lastUpdate}`)
.fontSize(14)
.fontColor(Color.Gray)
}
Button('手动刷新')
.width(200)
.onClick(() => {
this.checkStatus();
})
}
.width('100%')
.height('100%')
.padding(20)
}
private getStatusText(): string {
const statusMap: Record<string, string> = {
'pending': '审核中',
'approved': '审核通过',
'rejected': '审核未通过',
'error': '获取状态失败'
};
return statusMap[this.status] || this.status;
}
private getStatusColor(): Color {
const colorMap: Record<string, Color> = {
'pending': Color.Blue,
'approved': Color.Green,
'rejected': Color.Red,
'error': Color.Orange
};
return colorMap[this.status] || Color.Black;
}
}
签名文件生成流程
// 密钥生成配置类
class KeyStoreGenerator {
static generateKeyStore(config: {
storeFile: string,
password: string,
alias: string,
validity: number, // 年数
organization: string,
countryCode: string
}): void {
// 在DevEco Studio中执行:
// Build > Generate Key and CSR
// 按照向导填写相应信息
}
}
// 发布证书申请流程
class CertificateManager {
static async applyReleaseCertificate(csrFile: string): Promise<string> {
// 在AGC控制台操作:
// 用户与访问 > 证书管理 > 新增证书
// 选择"发布证书"类型,上传CSR文件
return "certificate.cer";
}
}
四、常见问题与解决方案
1. 签名相关问题
问题: "HarmonyOS hapAppProvision文件非法"
- 原因: Profile文件与当前应用不匹配
- 解决: 检查Profile文件中的bundle-name是否与待发布应用包名一致
问题: "证书和Profile不匹配"
- 原因: 发布证书与Profile文件中使用的证书不一致
- 解决: 确保打包时使用的证书与申请Profile时使用的证书一致
2. 包体规范问题
问题: 软件包大小超限
- 限制: 主包≤2GB,智慧屏/手表HAP包≤20MB
- 解决: 优化资源文件,使用动态加载
3. 审核被拒处理
// 重新提交审核
static async resubmitAfterRejection(
appId: string,
trackingId: string,
fixes: {
updatedHapPath?: string,
updatedPrivacyPolicy?: string
}
): Promise<boolean> {
// 根据审核反馈进行修复后重新提交
return true;
}
五、总结
✅ 关键知识点
- 应用签名是HarmonyOS应用上架的必要条件
- 发布证书和Profile文件必须匹配且有效
- 包体大小和内容规范需要严格遵守
- 审核流程需要耐心等待和及时响应
🔧 核心流程
- 准备阶段: 生成密钥 → 申请证书 → 配置签名
- 构建阶段: 编译打包 → 包体检查 → 预发布测试
- 提交阶段: 上传软件包 → 填写应用信息 → 提交审核
- 发布阶段: 审核跟踪 → 问题修复 → 正式上架
💡 最佳实践建议
- 提前规划: 证书有效期建议设置25年以上
- 测试充分: 使用真机测试所有功能,特别是权限相关功能
- 材料准备: 提前准备好应用截图、图标、隐私政策等材料
- 关注规范: 严格遵守华为应用市场的设计和内容规范
- 及时响应: 审核期间保持关注,及时处理审核反馈
通过本系列教程的学习,你已经掌握了从HarmonyOS开发入门到应用上架的全流程技能。继续实践和探索,你将能够开发出更加优秀的HarmonyOS应用!
浙公网安备 33010602011771号