一键发布鸿蒙5应用:AGC上架审核流程详解

一、应用发布前准备

  1. 配置应用签名
    在entry/build-profile.json5中配置签名信息:

{
"app": {
"signingConfigs": [
{
"name": "release",
"material": {
"certpath": "signing/release.p12",
"storePassword": "yourpassword",
"keyAlias": "release",
"keyPassword": "yourpassword",
"profile": "signing/release.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "signing/release.jks"
}
}
]
}
}
2. 构建发布版本HAP
在DevEco Studio终端执行:

./gradlew assembleRelease
或使用图形界面:

点击菜单栏"Build" > "Build HAP(s)/APP(s)" > "Build Release HAP"
二、AGC控制台应用创建

  1. 创建新应用
    // 伪代码:模拟AGC应用创建API调用
    async function createAGCApp(appInfo: {
    appName: string,
    packageName: string,
    category: string,
    defaultLanguage: string
    }) {
    const response = await fetch('https://connect-api.cloud.huawei.com/api/v1/apps', {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    'Authorization': Bearer ${await getAGCToken()}
    },
    body: JSON.stringify(appInfo)
    });

return await response.json();
}

// 示例调用
createAGCApp({
appName: "我的鸿蒙应用",
packageName: "com.example.myharmonyapp",
category: "工具",
defaultLanguage: "zh-CN"
});
三、应用信息配置

  1. 基本信息配置
    在AGC控制台填写:

应用名称(中英文)
应用分类
默认语言
应用简介(200字符内)
应用描述(2000字符内)
2. 隐私政策配置
创建privacy.html并上传:

隐私政策

隐私政策

最后更新时间:2023年10月

<h2>1. 信息收集</h2>
<p>我们可能会收集以下信息:</p>
<ul>
    <li>设备信息(型号、操作系统版本)</li>
    <li>使用数据(功能使用情况)</li>
</ul>

<h2>2. 信息使用</h2>
<p>收集的信息将用于:</p>
<ul>
    <li>改进应用功能</li>
    <li>分析用户行为</li>
</ul>
四、应用包上传与版本管理 1. 上传HAP文件 使用AGC API上传示例:

async function uploadHAPFile(appId: string, filePath: string) {
const formData = new FormData();
formData.append('file', new Blob([await fs.readFile(filePath)]));

const response = await fetch(
https://connect-api.cloud.huawei.com/api/v1/apps/${appId}/packages,
{
method: 'POST',
headers: {
'Authorization': Bearer ${await getAGCToken()}
},
body: formData
}
);

return await response.json();
}
2. 配置版本信息
async function setVersionInfo(appId: string, version: {
versionCode: number,
versionName: string,
releaseNotes: Record<string, string>
}) {
const response = await fetch(
https://connect-api.cloud.huawei.com/api/v1/apps/${appId}/versions,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${await getAGCToken()}
},
body: JSON.stringify(version)
}
);

return await response.json();
}
五、审核前自检工具实现

  1. 自动化检查脚本
    创建precheck.ets:

import bundleManager from '@ohos.bundle.bundleManager';
import permission from '@ohos.permission';

export class AppPublishChecker {
// 检查必要权限声明
static async checkRequiredPermissions(): Promise<string[]> {
const requiredPerms = [
permission.Permission.INTERNET,
permission.Permission.READ_MEDIA,
permission.Permission.WRITE_MEDIA
];

const missingPerms: string[] = [];
const bundleInfo = await bundleManager.getBundleInfoForSelf();

for (const perm of requiredPerms) {
  if (!bundleInfo.reqPermissions.includes(perm)) {
    missingPerms.push(perm);
  }
}

return missingPerms;

}

// 检查隐私政策链接
static async checkPrivacyPolicy(): Promise {
try {
const httpRequest = http.createHttp();
const response = await httpRequest.request(
'https://www.yourdomain.com/privacy.html',
{ method: 'HEAD' }
);

  return response.responseCode === 200;
} catch {
  return false;
}

}

// 检查应用图标
static async checkAppIcons(): Promise {
const bundleInfo = await bundleManager.getBundleInfoForSelf();
return !!bundleInfo.icons.length;
}

// 运行全部检查
static async runFullCheck(): Promise<{
passed: boolean,
details: Record<string, any>
}> {
const results = {
permissions: await this.checkRequiredPermissions(),
privacyPolicy: await this.checkPrivacyPolicy(),
icons: await this.checkAppIcons()
};

return {
  passed: results.permissions.length === 0 && 
         results.privacyPolicy && 
         results.icons,
  details: results
};

}
}
六、一键发布脚本实现

  1. 完整发布流程脚本
    创建publish.ets:

import fs from '@ohos.file.fs';
import http from '@ohos.net.http';

export class AppPublisher {
private static readonly AGC_API = 'https://connect-api.cloud.huawei.com';

// 获取AGC访问令牌
private static async getAGCToken(): Promise {
const auth = agconnect.auth();
const user = auth.currentUser;

if (!user) {
  throw new Error('请先登录AGC账号');
}

return await user.getToken();

}

// 上传HAP文件
private static async uploadPackage(appId: string, hapPath: string): Promise {
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) {
  console.error('上传HAP失败:', error);
  throw error;
}

}

// 提交审核
private static async submitForReview(appId: string, versionId: string): Promise {
const token = await this.getAGCToken();
const httpRequest = http.createHttp();

try {
  const response = await httpRequest.request(
    `${this.AGC_API}/api/v1/apps/${appId}/versions/${versionId}/submit`,
    {
      method: 'POST',
      header: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  return JSON.parse(response.result);
} catch (error) {
  console.error('提交审核失败:', error);
  throw error;
}

}

// 一键发布
static async publish(appId: string, hapPath: string): Promise {
try {
console.log('开始应用发布流程...');

  // 1. 运行预检查
  const precheck = await AppPublishChecker.runFullCheck();
  if (!precheck.passed) {
    console.error('预检查未通过:', precheck.details);
    return false;
  }
  
  // 2. 上传HAP
  console.log('上传HAP文件中...');
  const uploadResult = await this.uploadPackage(appId, hapPath);
  console.log('上传成功,包ID:', uploadResult.packageId);
  
  // 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;
}

}
}
七、审核状态监控

  1. 审核状态查询组件
    @Entry
    @Component
    struct ReviewStatusPage {
    @State appId: string = '';
    @State trackingId: string = '';
    @State status: string = 'loading';
    @State lastCheck: string = '';

private timer: number = 0;

onPageShow() {
const params = router.getParams();
if (params) {
this.appId = params.appId;
this.trackingId = params.trackingId;
this.checkStatus();
this.startPolling();
}
}

onPageHide() {
this.stopPolling();
}

startPolling() {
this.timer = setInterval(() => {
this.checkStatus();
}, 300000); // 每5分钟检查一次
}

stopPolling() {
if (this.timer) {
clearInterval(this.timer);
}
}

async checkStatus() {
try {
const httpRequest = http.createHttp();
const token = await agconnect.auth().currentUser?.getToken();

  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.lastCheck = 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 === 'loading') {
    LoadingProgress()
  } else {
    Text(`状态: ${this.getStatusText()}`)
      .fontSize(20)
      .fontColor(this.getStatusColor())
    
    Text(`最后检查: ${this.lastCheck}`)
      .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;
}
}
八、常见审核问题处理

  1. 审核拒绝常见原因及解决方案
    拒绝原因 解决方案 代码示例
    ​​隐私政策不完整​​ 补充隐私政策内容 [见第三章隐私政策配置]
    ​​权限声明不足​​ 添加缺失权限声明 module.json5中添加reqPermissions
    ​​应用图标缺失​​ 提供多尺寸应用图标 确保resources/base/media包含图标文件
    ​​功能描述不符​​ 修改应用描述 更新AGC控制台的应用描述

  2. 快速修复与重新提交
    // 在AppPublisher中添加
    static async resubmitAfterRejection(
    appId: string,
    trackingId: string,
    fixes: {
    updatedHapPath?: string,
    updatedPrivacyPolicy?: string,
    updatedDescription?: string
    }
    ): Promise {
    try {
    // 1. 更新应用信息
    if (fixes.updatedPrivacyPolicy || fixes.updatedDescription) {
    await this.updateAppInfo(appId, {
    privacyPolicy: fixes.updatedPrivacyPolicy,
    description: fixes.updatedDescription
    });
    }

    // 2. 上传新版本(如果有)
    if (fixes.updatedHapPath) {
    await this.uploadPackage(appId, fixes.updatedHapPath);
    }

    // 3. 重新提交审核
    const response = await http.createHttp().request(
    ${this.AGC_API}/api/v1/apps/${appId}/reviews/${trackingId}/resubmit,
    {
    method: 'POST',
    header: {
    'Authorization': Bearer ${await this.getAGCToken()}
    }
    }
    );

    return JSON.parse(response.result).success;
    } catch (error) {
    console.error('重新提交失败:', error);
    return false;
    }
    }
    九、发布后管理

  3. 版本回滚实现
    // 在AppPublisher中添加
    static async rollbackVersion(appId: string, versionCode: number): Promise {
    try {
    const response = await http.createHttp().request(
    ${this.AGC_API}/api/v1/apps/${appId}/versions/${versionCode}/rollback,
    {
    method: 'POST',
    header: {
    'Authorization': Bearer ${await this.getAGCToken()}
    }
    }
    );

    return JSON.parse(response.result).success;
    } catch (error) {
    console.error('版本回滚失败:', error);
    return false;
    }
    }

  4. 分阶段发布控制
    // 在AppPublisher中添加
    static async stagedRollout(
    appId: string,
    versionCode: number,
    percentage: number
    ): Promise {
    if (percentage < 1 || percentage > 100) {
    throw new Error('百分比必须在1-100之间');
    }

try {
const response = await http.createHttp().request(
${this.AGC_API}/api/v1/apps/${appId}/versions/${versionCode}/rollout,
{
method: 'POST',
header: {
'Authorization': Bearer ${await this.getAGCToken()},
'Content-Type': 'application/json'
},
extraData: JSON.stringify({ percentage })
}
);

return JSON.parse(response.result).success;

} catch (error) {
console.error('分阶段发布设置失败:', error);
return false;
}
}
总结
通过本文的学习,你已经掌握了鸿蒙5应用通过AGC一键发布的完整流程:

​​前期准备​​:签名配置与HAP打包
​​应用创建​​:AGC控制台应用信息配置
​​审核自检​​:自动化检查工具实现
​​一键发布​​:完整发布脚本开发
​​状态监控​​:审核进度实时跟踪
​​发布管理​​:版本控制与分阶段发布
AGC提供的发布流程为开发者带来了:

​​高效发布​​:简化应用上架流程
​​智能审核​​:自动化检查提高通过率
​​灵活控制​​:版本管理和分阶段发布
​​全面监控​​:实时跟踪审核状态
在实际项目开发中,你还可以进一步探索:

与CI/CD流水线的深度集成
自动化测试与发布的结合
多环境发布策略管理
应用审核数据分析与优化

posted @ 2025-06-28 23:03  暗雨YA  阅读(75)  评论(0)    收藏  举报