摘要: 本文记录我开发一款鸿蒙 PC 端分布式 Markdown 笔记应用并完成应用市场上架的全过程。从需求设计、编辑器内核实现、分布式数据同步、PC 端窗口适配,到上架资质准备、审核避坑、上架后优化迭代,覆盖应用落地完整链路。开发过程中遇到分布式数据冲突、窗口生命周期、软键盘遮挡、审核被拒 4 类共 6 个真实踩坑问题,逐一给出定位与解法。应用上架后 30 天内下载 4200 次,评分 4.6 星,分布式同步延迟 180ms。

环境说明: DevEco Studio 5.0.5、HarmonyOS PC 5.0.1、API 18(PC 专属能力)、分布式数据管理服务 version 2.1

鸿蒙 PC 桌面运行 Markdown 笔记应用截图

背景与痛点

我一直在用 Typora 写技术笔记,但换到鸿蒙 PC 后没有合适的 Markdown 编辑器。市面上的鸿蒙应用主要集中在手机端,PC 端生产力工具几乎是空白。正好赶上开源鸿蒙 PC 赛事,我决定自己开发一款 Markdown 笔记应用,名字叫「分布式笔记」。

选这个方向有三个考虑:

  • 刚需:鸿蒙 PC 缺少好用的 Markdown 编辑器,上架后有真实用户价值
  • 展示分布式能力:鸿蒙的分布式数据管理是核心卖点,笔记跨设备同步是天然场景
  • 上架难度适中:笔记类应用不涉及支付、社交等敏感能力,审核相对可控

但真正动手后才发现,从「能跑的 Demo」到「能过审上架的应用」之间有巨大的工程量。我前后经历了三轮审核被拒,累计修改 17 个问题项,从提交到过审花了 22 天。这篇文章把完整流程记录下来,重点是审核被拒的原因和修复方案,希望能帮准备上架的开发者少走弯路。

应用需求设计与技术选型

2.1 核心功能需求

经过两周的用户调研(在鸿蒙 PC 社区发帖收集需求),最终确定的功能优先级:

优先级功能说明工作量
P0Markdown 编辑 + 实时预览分栏布局,左侧编辑右侧预览3 天
P0本地文件管理新建/保存/打开 .md 文件2 天
P0分布式同步跨设备笔记自动同步4 天
P1快捷键体系Ctrl+S 保存、Ctrl+B 加粗等1 天
P1主题切换明暗主题 + 代码高亮主题1 天
P2导出 PDF把 Markdown 导出为 PDF2 天
P2目录树多文件管理,文件夹嵌套2 天

P0 功能是上架最小可行产品,P1/P2 在版本迭代中补充。

2.2 技术选型决策

自研 TextArea

RichEditor 组件

WebView + 开源编辑器

否,纯Markdown

技术选型

编辑器内核

灵活可控
但工作量大

系统组件
功能受限

功能完整
但性能差

是否需要富文本?

选自研 TextArea
+ 自定义解析器

最终技术方案:

  • 编辑器:自研 TextArea + 自写 Markdown 解析器。鸿蒙 PC 的 RichEditor 组件不支持自定义语法高亮,WebView 方案在 PC 端内存占用过高(200MB+),自研最可控
  • 预览:ArkUI 原生组件渲染,把 Markdown AST 映射成 ArkUI 组件树,不用 WebView
  • 分布式同步:鸿蒙分布式数据管理服务(distributedData),KV 数据模型,笔记内容按段落分片存储
  • 文件存储:应用沙箱 + 用户文档目录双写,沙箱用于分布式同步,文档目录用于用户直接访问

核心功能开发

3.1 编辑器内核实现

编辑器核心是 TextArea 的文本变化监听 + Markdown 实时解析。解析器用纯 ArkTS 实现,支持 CommonMark 基础语法 + GFM 表格扩展。

文本变化监听与增量解析:

// EditorComponent.ets - 编辑器组件
// 为什么用增量解析而非全量解析:文档超过 5000 字时全量解析耗时 80ms+,
// 增量解析只处理变化段落,耗时降到 5ms 以内
@Component
export struct EditorComponent {
  @State private rawText: string = ''
  @State private astNodes: MarkdownNode[] = []
  private parser: MarkdownParser = new MarkdownParser()
  private lastParsePosition: number = 0

  build() {
    TextArea({ placeholder: '开始输入 Markdown...' })
      .width('50%')
      .height('100%')
      .fontSize(16)
      .fontColor($r('app.color.editor_text'))
      .backgroundColor($r('app.color.editor_bg'))
      .onChange((value: string) => {
        // 计算变化区域,只重新解析受影响的段落
        const changeRange = this.detectChangeRange(this.rawText, value)
        this.rawText = value
        this.incrementalParse(changeRange)
      })
  }

  private detectChangeRange(oldText: string, newText: string): ChangeRange {
    // 找前后文本的第一个差异点和最后一个差异点
    let start = 0
    while (start < oldText.length && start < newText.length
           && oldText[start] === newText[start]) {
      start++
    }
    let oldEnd = oldText.length - 1
    let newEnd = newText.length - 1
    while (oldEnd >= start && newEnd >= start
           && oldText[oldEnd] === newText[newEnd]) {
      oldEnd--; newEnd--
    }
    // 找到变化所在的段落边界(双换行符)
    return this.expandToParagraph(newText, start, newEnd + 1)
  }

  private incrementalParse(range: ChangeRange) {
    // 只重新解析变化段落,替换 AST 中对应节点
    const newNodes = this.parser.parseParagraphs(this.rawText, range)
    this.astNodes = this.mergeAstNodes(this.astNodes, newNodes, range)
    // 触发预览区更新
    AppStorage.setOrCreate('previewAst', this.astNodes)
  }
}

3.2 预览区渲染

预览区把 Markdown AST 映射成 ArkUI 组件树。关键是递归渲染不同节点类型:

// PreviewComponent.ets - 预览组件
@Component
export struct PreviewComponent {
  @StorageLink('previewAst') private astNodes: MarkdownNode[] = []

  build() {
    Scroll() {
      Column() {
        ForEach(this.astNodes, (node: MarkdownNode) => {
          this.renderNode(node)
        }, (node: MarkdownNode) => node.id)
      }
      .width('100%')
      .padding(16)
    }
    .width('50%')
    .height('100%')
    .scrollBar(BarState.Auto)
  }

  @Builder renderNode(node: MarkdownNode) {
    if (node.type === 'heading') {
      Text(node.text)
        .fontSize(28 - (node.level - 1) * 4)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 16, bottom: 8 })
    } else if (node.type === 'paragraph') {
      Text(this.renderInline(node.children))
        .fontSize(16)
        .lineHeight(24)
        .margin({ bottom: 12 })
    } else if (node.type === 'code_block') {
      this.renderCodeBlock(node)
    } else if (node.type === 'table') {
      this.renderTable(node)
    }
    // ... 其他节点类型
  }
}

3.3 分布式数据同步

这是应用的核心卖点,也是开发中最复杂的部分。鸿蒙分布式数据管理提供 KV 数据模型,多设备间自动同步。

同步架构:

设备 B - 鸿蒙手机

分布式数据服务

设备 A - 鸿蒙 PC

编辑器
本地修改

本地 KVStore
notes_kv

同步引擎
监听变更

分布式 KVStore
自动同步

冲突解决
LWW 策略

同步引擎
监听变更

本地 KVStore
notes_kv

编辑器
收到更新

同步引擎实现:

// DistributedSync.ets - 分布式同步引擎
// 为什么按段落分片存储而非整篇存储:整篇文档作为单个 KV 存储时,
// 任何修改都会触发全量同步(50KB 文档同步耗时 800ms)。
// 按段落分片后,只同步变化的段落(5KB),耗时降到 180ms。
import distributedData from '@ohos.data.distributedData';

export class DistributedSync {
  private kvStore: distributedData.KVStore = null
  private storeId: string = 'notes_kv_store'

  async init(): Promise<void> {
    // 创建分布式 KVStore
    const config: distributedData.KVStoreConfig = {
      createStore: false,
      autoSync: true,  // 自动同步模式
      securityLevel: distributedData.SecurityLevel.S1,
    }
    const manager = distributedData.createKVManager(config)
    this.kvStore = await manager.getKVStore(this.storeId, config)

    // 监听远程数据变更
    this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_REMOTE,
      (data: distributedData.ChangeNotification) => {
        this.handleRemoteChange(data)
      })
  }

  // 保存段落到分布式存储
  async saveParagraph(noteId: string, paraId: string, content: string): Promise<void> {
    const key = `${noteId}::${paraId}`
    const value: NoteParagraph = {
      content: content,
      version: Date.now(),  // 用于 LWW 冲突解决
      deviceId: this.getDeviceId(),
    }
    await this.kvStore.put(key, JSON.stringify(value))
  }

  // 处理远程变更
  private handleRemoteChange(data: distributedData.ChangeNotification): void {
    for (const entry of data.insertEntries) {
      this.applyRemoteParagraph(entry.key, entry.value)
    }
    for (const entry of data.updateEntries) {
      this.applyRemoteParagraph(entry.key, entry.value)
    }
  }
}

PC 端窗口与兼容性适配

鸿蒙 PC 和手机端最大的差异是窗口管理。PC 应用运行在窗口化环境中,需要处理窗口缩放、多窗口、键盘快捷键等手机端不需要的问题。

4.1 窗口生命周期适配

// EntryAbility.ets - 入口 Ability,处理窗口生命周期
import window from '@ohos.window';

export default class EntryAbility extends UIAbility {
  private windowInstance: window.Window = null

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // PC 端设置窗口最小尺寸,防止缩太小后布局崩溃
    windowStage.getMainWindow().then((win) => {
      this.windowInstance = win
      win.setMinimumWindowSize(800, 500)  // 最小 800x500

      // 监听窗口尺寸变化,做响应式布局
      win.on('windowSizeChange', (size: window.Size) => {
        AppStorage.setOrCreate('windowWidth', size.width)
        AppStorage.setOrCreate('windowHeight', size.height)
        // 宽度 < 1000 时切换为单栏布局
        AppStorage.setOrCreate('isCompactMode', size.width < 1000)
      })
    })

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(0x0000, 'EntryAbility', `加载失败: ${err.message}`)
      }
    })
  }
}

4.2 响应式布局

// Index.ets - 主页面,根据窗口宽度切换布局
@Entry
@Component
struct Index {
  @StorageLink('isCompactMode') private isCompact: boolean = false

  build() {
    if (this.isCompact) {
      // 窄窗口:单栏模式,编辑和预览切换显示
      this.compactLayout()
    } else {
      // 宽窗口:分栏模式,左编辑右预览
      this.splitLayout()
    }
  }

  @Builder splitLayout() {
    Row() {
      EditorComponent()
      Divider().vertical(true).height('100%')
      PreviewComponent()
    }
    .width('100%').height('100%')
  }

  @Builder compactLayout() {
    // 用 Tab 切换编辑/预览
    Tabs() {
      TabContent() { EditorComponent() }.tabBar('编辑')
      TabContent() { PreviewComponent() }.tabBar('预览')
    }
    .width('100%').height('100%')
  }
}

4.3 键盘快捷键体系

PC 端用户重度依赖快捷键。鸿蒙 PC 通过 onKeyEvent 监听键盘事件:

// 快捷键绑定
TextArea({})
  .onKeyEvent((event: KeyEvent) => {
    if (event.type === KeyType.Down) {
      const ctrl = event.ctrlKey
      const key = event.keyCode

      if (ctrl && key === KeyCode.KEY_S) {
        this.saveCurrentNote()
        return true  // 消费事件,阻止默认行为
      }
      if (ctrl && key === KeyCode.KEY_B) {
        this.wrapSelection('**')
        return true
      }
      if (ctrl && key === KeyCode.KEY_I) {
        this.wrapSelection('*')
        return true
      }
      // ... 其他快捷键
    }
    return false
  })

应用上架资质准备

上架应用市场需要准备一系列资质材料,这一步看似是文档工作,但材料不齐会被直接打回,不进入审核流程。

5.1 资质清单

材料说明耗时
软件著作权软著证书或申请受理通知书3 天(加急)
隐私政策应用权限说明 + 数据处理声明1 天
用户协议使用条款 + 免责声明1 天
应用图标512x512 PNG + 圆角处理0.5 天
应用截图至少 3 张,1920x10800.5 天
应用描述50-500 字功能介绍0.5 天
测试账号如需登录则提供测试账号-

5.2 隐私政策要点

隐私政策是审核重点,必须如实声明应用使用的权限和数据处理方式:

《分布式笔记隐私政策》核心条款:

1. 数据收集范围
   - 本应用仅收集您主动输入的笔记内容
   - 不收集设备标识符、位置信息、通讯录等敏感数据
   - 不接入任何第三方 SDK

2. 数据存储与同步
   - 笔记内容存储在应用沙箱目录,仅您本人可访问
   - 分布式同步通过鸿蒙系统分布式数据服务完成
   - 同步数据在设备间端到端加密传输,不经过第三方服务器

3. 权限使用说明
   - ohos.permission.DISTRIBUTED_DATASYNC:用于跨设备笔记同步
   - ohos.permission.FILE_ACCESS_USER_SELECTED:用于读写用户选择的文件
   - 以上权限均在您主动操作时申请,不后台静默使用

4. 数据删除
   - 您可随时在应用内删除笔记,数据将永久清除
   - 卸载应用后,所有本地数据将自动删除

5.3 module.json5 权限声明

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "$string:permission_distributed_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.FILE_ACCESS_USER_SELECTED",
        "reason": "$string:permission_file_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

关键点:每个权限必须有 reason 说明使用目的,when 必须是 inuse(使用时申请)而非 always(后台常驻),否则审核会被拒。


应用市场审核踩坑与避坑技巧

这是全文最核心的部分。我经历了三轮审核,记录每次被拒的原因和修复方案。

6.1 第一轮被拒:隐私政策不合规

审核反馈:

审核结果:不通过
问题项 1:隐私政策中未说明分布式同步的数据加密方式
问题项 2:权限 DISTRIBUTED_DATASYNC 的 reason 描述过于简略
问题项 3:应用描述中包含"最佳"字样,违反新广告法

修复方案:

问题 1:隐私政策补充加密方式说明(见 5.2 节,增加了"端到端加密传输"条款)。

问题 2:权限 reason 从"用于数据同步"改为完整描述:

{
  "name": "ohos.permission.DISTRIBUTED_DATASYNC",
  "reason": "$string:permission_distributed_reason"
}
// resources/string.json
"permission_distributed_reason": "用于在您的鸿蒙设备间同步笔记内容,"
  "数据通过系统分布式数据服务端到端加密传输,不经过第三方服务器"

问题 3:应用描述把"鸿蒙 PC 最佳 Markdown 编辑器"改为"鸿蒙 PC 端 Markdown 编辑器,支持分布式同步"。

经验:审核对"最"“第一”"最佳"等绝对化用语零容忍,提交前全文搜索这些词。

6.2 第二轮被拒:功能问题与崩溃

审核反馈:

审核结果:不通过
问题项 1:在 PC 端窗口缩放到最小尺寸时,编辑区内容被截断不可见
问题项 2:分布式同步开关关闭后,仍后台发起同步请求
问题项 3:测试机上报崩溃 1 次(空指针),堆栈在 PreviewComponent:42

修复方案:

问题 1:设置窗口最小尺寸 800x500(见 4.1 节),并在宽度 < 1000 时切换为单栏 Tab 布局。

问题 2:同步开关关闭时,取消 KVStore 订阅:

// 设置同步开关
setSyncEnabled(enabled: boolean): void {
  if (enabled) {
    this.kvStore.on('dataChange', ...)
  } else {
    // 关闭时必须取消订阅,否则后台仍会收到同步数据
    this.kvStore.off('dataChange')
    this.kvStore = null
  }
}

问题 3:预览组件空指针崩溃,原因是 AST 节点的 children 可能为 null 但渲染时未判空:

// 修复前
Text(this.renderInline(node.children))

// 修复后
Text(this.renderInline(node.children ?? []))

经验:审核会在多种窗口尺寸下测试,必须在 800x500 到 1920x1080 全尺寸范围验证布局。同步类功能必须确保开关可完全关闭,不能有后台残留。

6.3 第三轮被拒:兼容性与细节

审核反馈:

审核结果:不通过
问题项 1:在 HarmonyOS PC 4.1 版本上启动崩溃(API 16 不兼容)
问题项 2:应用图标在深色主题下不可见(白色图标无背景)
问题项 3:截图与实际应用界面不符(截图是旧版本)

修复方案:

问题 1:build-profile.json5 的 compatibleSdkVersion 从 18 改为 16,并对 API 16 缺少的能力做降级处理:

// 检查 API 版本做降级
import deviceInfo from '@ohos.deviceInfo';

const apiVersion = deviceInfo.firstApiVersion
if (apiVersion >= 18) {
  // 使用 API 18 的窗口最小尺寸 API
  win.setMinimumWindowSize(800, 500)
} else {
  // API 16 降级:不设置最小尺寸,用 CSS 媒体查询做响应式
}

问题 2:应用图标改为带圆角背景的 SVG,明暗主题下都可见。

问题 3:重新截取应用截图,确保与提交版本完全一致。

经验:截图必须在最终版本上重新截取,不能复用开发中途的截图。兼容版本要在真机上测试,模拟器可能无法复现崩溃。

6.4 第四轮通过

前三轮修复后,第四轮审核通过:

应用市场审核通过截图

审核结果:通过
审核耗时:22 天(4 轮)
应用大小:8.7 MB
上架版本:1.0.0

6.5 审核避坑技巧汇总

提交审核前自检

文案检查

功能检查

兼容性检查

资质检查

搜索绝对化用语
最/第一/最佳

隐私政策与实际权限一致

全窗口尺寸测试

开关功能可完全关闭

无空指针/崩溃

最低兼容版本真机测试

深色主题图标可见

截图与最终版本一致

软著证书有效

权限 reason 完整

提交


分布式特性调试

分布式同步是应用的核心能力,也是调试最困难的部分——需要多设备环境,且同步时序不易复现。

7.1 多设备调试环境搭建

DevEco Studio 支持同时连接多台设备调试。我用了 1 台鸿蒙 PC + 1 台鸿蒙手机搭建调试环境:

# 查看已连接设备
hdc list targets
# 输出:
#   192.168.1.108:5555  (PC)
#   192.168.1.233:5555  (Phone)

# 同时安装到两台设备
hdc install -s 192.168.1.108:5555 entry-default-signed.hap
hdc install -s 192.168.1.233:5555 entry-default-signed.hap

# 查看分布式同步日志
hdc shell hilog | grep -E "distributedData|KVStore"

7.2 同步延迟实测

在 PC 端编辑一个段落,测量手机端收到同步数据的延迟:

场景同步延迟说明
同 WiFi,小段落 (1KB)180ms正常场景
同 WiFi,大段落 (50KB)680ms整篇同步,已优化为分片
同 WiFi,分片后 (5KB)210ms按段落分片同步
跨网络 (不同 WiFi)1200ms经过云端中转
离线后上线3.2s补偿同步全量数据

分布式同步实测截图


开发过程踩坑总结

除了审核被拒的问题,开发过程中还有几个值得记录的坑。

8.1 踩坑一:分布式数据冲突,后写覆盖先写但版本号丢失

现象:PC 和手机同时编辑同一段落,同步后发现一边的修改丢失了。

原因:分布式数据服务的默认冲突解决策略是 LWW(Last Write Wins),基于数据的系统时间戳。但 PC 和手机的系统时间可能不同步,导致时间戳判断不准。

解决方案:在 value 中携带应用层版本号(Date.now() + 设备 ID 偏移),手动实现冲突解决:

private applyRemoteParagraph(key: string, valueStr: string): void {
  const remote: NoteParagraph = JSON.parse(valueStr)
  const local = this.localCache.get(key)

  if (local && remote.version <= local.version) {
    // 远程版本更旧,丢弃
    return
  }
  // 远程版本更新,应用变更
  this.localCache.set(key, remote)
  this.notifyEditorUpdate(key, remote.content)
}

8.2 踩坑二:TextArea 在 PC 端中文输入法重复触发 onChange

现象:用拼音输入法打中文时,onChange 被重复触发,导致解析器收到中间态文本(如"ni hao"→"你好"过程中触发多次)。

原因:鸿蒙 PC 的 TextArea 在输入法组合态时会触发 onChange,传入的是中间态文本。

解决方案:用 onTextChange 替代 onChange,onTextChange 只在输入法提交后触发:

TextArea({})
  // 错误:onChange 在输入法组合态重复触发
  // .onChange((value: string) => { ... })

  // 正确:onTextChange 只在提交后触发
  .onTextChange((value: string) => {
    this.handleTextChange(value)
  })

8.3 踩坑三:窗口最小尺寸设置在 API 16 上崩溃

现象:调用 win.setMinimumWindowSize(800, 500) 在 HarmonyOS PC 4.1 上报 function not found 崩溃。

原因:setMinimumWindowSize 是 API 18 新增接口,API 16 不存在。

解决方案:运行时检查 API 版本做降级(见 6.3 节问题 1 的修复)。

经验:PC 专属 API 普遍从 API 18 开始引入,如果兼容版本低于 18,所有 PC 专属接口都要做版本判断。

8.4 踩坑四:应用图标圆角处理不一致

现象:应用图标在桌面上显示有圆角,但在应用市场详情页显示为直角,审核反馈"图标不规范"。

原因:鸿蒙桌面会自动给图标加圆角遮罩,但应用市场详情页显示原图。如果图标本身有圆角,叠加后会出现双重圆角。

解决方案:图标设计为直角方形,让系统统一加圆角遮罩。不要在图标里自己画圆角。


上架后优化迭代

应用上架后,根据用户反馈做了两轮优化迭代。

9.1 v1.0.1 修复(上架后第 3 天)

问题优先级修复方式
大文件 (>10万字) 编辑卡顿P0增量解析优化,虚拟滚动
导出 PDF 中文乱码P0嵌入中文字体子集
快捷键 Ctrl+Z 撤销不工作P1接入系统 UndoManager

9.2 v1.1.0 功能更新(上架后第 14 天)

  • 代码块语法高亮(支持 20+ 语言)
  • 目录树多文件管理
  • 导出 HTML
  • 自定义 CSS 主题

9.3 运营数据

上架 30 天后的数据:

下载量:        4,200 次
日活用户:      380
评分:          4.6 / 5.0
主要反馈:      "终于有能用的 Markdown 编辑器了"(好评)
              "希望支持 Mermaid 图表"(功能建议)
              "分布式同步很惊艳"(好评)

崩溃率:        0.03%
ANR 率:        0.01%
同步成功率:    99.7%

小结:PC 端上架的关键收获

10.1 核心结论

这款分布式 Markdown 笔记应用从立项到上架历时 35 天(开发 13 天 + 审核 22 天),最终上架后 30 天下载 4200 次,评分 4.6 星。几个关键收获:

  • 审核是最不可控的环节:开发 13 天,审核花了 22 天,4 轮才过。提前对照审核规范自检,能大幅减少被拒轮次
  • 分布式能力是差异化卖点:用户反馈中"分布式同步"是提及最多的好评点,鸿蒙 PC 应用要充分利用这个平台优势
  • PC 适配不是可选项:窗口管理、快捷键、响应式布局这些 PC 专属能力不做的话用户体验直接不及格

10.2 上架流程沉淀

经过这次完整流程,我沉淀了一套鸿蒙 PC 应用上架 checklist:

  1. 开发阶段:全窗口尺寸测试 + 最低兼容版本真机验证 + 输入法组合态测试
  2. 资质阶段:软著 + 隐私政策 + 用户协议 + 图标截图(截图必须最终版本重截)
  3. 自检阶段:绝对化用语搜索 + 权限 reason 完整性 + 开关功能可完全关闭
  4. 提交阶段:版本号 + 更新日志 + 测试账号(如需登录)

10.3 给开发者的建议

如果你也在开发鸿蒙 PC 应用准备上架,我的建议:

  1. 先把审核规范通读一遍,很多被拒原因(绝对化用语、权限 reason)在规范里明确写了,但容易忽略
  2. 截图在最终版本上截,不要复用开发中途的截图,这是最常见的被拒原因之一
  3. 兼容版本真机测试,模拟器无法复现所有崩溃,至少在最低兼容版本的真机上跑一遍
  4. 分布式功能确保可关闭,审核会测试关闭同步开关后是否还有后台行为
  5. 隐私政策与实际权限严格一致,声明了什么权限就只用什么权限,多余权限会被质疑

10.4 下一步规划

  • v1.2.0:支持 Mermaid 图表渲染(用户呼声最高的功能)
  • v1.3.0:支持 Markdown 表格编辑增强(可视化编辑)
  • v2.0.0:多端协同编辑(同一篇笔记多设备同时编辑,光标级同步)

如果本文对你有帮助,欢迎点赞、收藏、转发!
你在鸿蒙 PC 应用上架中遇到过哪些审核问题?欢迎在评论区交流~
行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激!


边界与已知限制

限制项具体表现规避方式
形态能力差异PC 端部分 Kit 与手机端不一致上架前核对目标形态能力清单
分布式前提同步依赖同账号、同网络与设备在线同步前校验前置条件
数据冲突多端同时编辑会产生冲突定义冲突策略并保留版本记录
窗口生命周期PC 多窗下生命周期与手机不同按窗口管理状态与资源释放
输入差异键鼠与触控交互范式不同分别适配快捷键、右键与手势
审核要求PC 专区审核要求与移动端不同单独准备 PC 端截图与说明

小结

PC 端应用的差异不在 ArkUI 写法,而在形态假设:窗口可自由缩放、输入是键鼠、多窗并存、能力有缺口。沿用手机端写法的部分,基本都要重做一遍交互与生命周期处理。

分布式能力则是另一个维度的复杂度——同步前校验前置条件,冲突时保留版本,这两件事决定了多端体验是"无缝"还是"数据丢失"。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐