HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uni-app路由管理神器:vue-router风格体验

路由拦截 路由守卫 路由

@meng-xi/uni-router

为 uni-app (Vue 3) 提供类似 vue-router 风格的路由管理系统(uni_modules 版本)。

⚠️ 仅支持 Vue 3 — 本库基于 Vue 3 Composition API(inject / ref / defineProps / defineEmits)和 app.provide 等 Vue 3 专属 API,不支持 uni-app Vue 2 项目。


特性

  • vue-router 风格 API - push / replace / relaunch / back,零学习成本
  • 路由守卫 - beforeEach / beforeResolve / afterEach / beforeEnter,支持 next(location, { mode }) 指定重定向方式
  • 命名路由 & 路由元信息 - 通过 name 导航,meta 携带自定义数据
  • TypeScript 类型提示 - 路由名称和路径自动补全与类型检查
  • uni API 拦截 - 可选拦截原生导航 API,统一守卫流程(interceptUniApi
  • 页面间通信 - useUniEventChannel 启用后所有导航方式均支持 eventChannel 双向通信,目标页通过 usePageChannel() 获取通道,基于 uni.$emit 全局事件总线,粘性缓存确保时序安全
  • 声明式导航 - RouterLink 组件,基于 uni navigator 封装,支持导航参数、动画、页面通信
  • 页面参数传递 - params 传递复杂数据,不暴露在 URL,支持 persistent 持久化
  • 查询参数增强 - queryInt() / queryNumber() / queryBool() 便捷解析
  • 导航动画 - push / replace / back 支持动画参数,仅 App 端生效
  • 路由状态同步 - syncRoute() 处理浏览器后退、物理返回键等场景
  • 错误处理 - 完整的 RouterError / NavigationFailure 体系,onError 全局捕获
  • 组合式 API - useRouter() / useRoute() / usePageChannel() 响应式访问路由与通信通道

安装

uni_modules(推荐)

mxuni-router 目录复制到项目的 uni_modules 目录下即可,无需 npm 安装。

npm

pnpm add @meng-xi/uni-router

npm 方式需将导入路径改为 @meng-xi/uni-router

快速开始

1. 创建路由器

// main.ts  
import { createSSRApp } from 'vue'  
import { createRouter } from './uni_modules/mxuni-router/js_sdk/index.js'  
import App from './App.vue'  

const router = createRouter({  
    routes: [  
        { path: 'pages/index/index', name: 'home', meta: { title: '首页' } },  
        { path: 'pages/about/about', name: 'about', meta: { title: '关于', requireAuth: true } }  
    ],  
    strict: true,  
    interceptUniApi: true, // 拦截 uni 原生导航 API,确保守卫生效  
    useUniEventChannel: true // 启用内置通信管理器,所有导航方式支持页面间双向通信  
})  

export function createApp() {  
    const app = createSSRApp(App)  
    app.use(router)  
    return { app }  
}

2. 路由导航

import { useRouter, useRoute } from './uni_modules/mxuni-router/js_sdk/index.js'  

const router = useRouter()  
const route = useRoute() // 返回响应式引用,路由变化时自动更新  

// 路径导航  
await router.push({ path: '/pages/about/about', query: { id: '1' } })  

// 命名导航  
await router.push({ name: 'about' })  

// 页面参数传递(params 不暴露在 URL,支持复杂数据)  
await router.push({ path: '/pages/detail/detail', params: { info: { name: 'Tom' } } })  

// 返回(执行完整守卫链)  
await router.back()

3. 页面间通信

启用 useUniEventChannel 后,所有导航方式均返回 eventChannel,目标页通过 usePageChannel() 获取通道:

// ===== 发起页 =====  
const result = await router.push({ path: '/pages/detail/detail' })  
result.eventChannel?.on('ready', data => console.log('目标页已就绪:', data))  
result.eventChannel?.emit('data', { msg: '发给目标页的数据' })  

// ===== 目标页(detail.vue)=====  
import { usePageChannel } from './uni_modules/mxuni-router/js_sdk/index.js'  

const channel = usePageChannel() // 无 __nav_id 时返回 noopChannel,无需判空  
channel.on('data', data => console.log('收到发起页数据:', data))  
channel.emit('ready', { status: 'ok' }) // 粘性缓存:发起页尚未注册 on 也能收到

4. 路由守卫

router.beforeEach((to, from, next) => {  
    if (to.meta.requireAuth && !isLoggedIn()) {  
        // 使用 replace 模式重定向,避免登录页之后残留受保护页面的历史  
        next({ name: 'login', query: { redirect: to.fullPath } }, { mode: 'replace' })  
    } else {  
        next()  
    }  
})

5. 自动生成路由配置(推荐)

配合 @meng-xi/vite-plugingenerateRouter 插件,可从 pages.json 自动生成路由配置和类型声明:

pnpm add @meng-xi/vite-plugin -D
// vite.config.ts  
import { defineConfig } from 'vite'  
import uni from '@dcloudio/vite-plugin-uni'  
import { generateRouter } from '@meng-xi/vite-plugin'  

export default defineConfig({  
    plugins: [  
        uni(),  
        generateRouter({  
            pagesJsonPath: 'src/pages.json',  
            outputPath: 'src/router.config.ts',  
            dts: true,  
            metaMapping: {  
                navigationBarTitleText: 'title',  
                requireAuth: 'requireAuth'  
            }  
        })  
    ]  
})

然后在 main.ts 中导入生成的路由配置:

import { createRouter } from './uni_modules/mxuni-router/js_sdk/index.js'  
import routes from './router.config'  

const router = createRouter({ routes })

文档

完整的 API 参考、配置项说明、RouterLink 组件属性、类型定义等请查阅官方网站:

📖 https://mengxi-studio.github.io/uni-router/

License

MIT

继续阅读 »

@meng-xi/uni-router

为 uni-app (Vue 3) 提供类似 vue-router 风格的路由管理系统(uni_modules 版本)。

⚠️ 仅支持 Vue 3 — 本库基于 Vue 3 Composition API(inject / ref / defineProps / defineEmits)和 app.provide 等 Vue 3 专属 API,不支持 uni-app Vue 2 项目。


特性

  • vue-router 风格 API - push / replace / relaunch / back,零学习成本
  • 路由守卫 - beforeEach / beforeResolve / afterEach / beforeEnter,支持 next(location, { mode }) 指定重定向方式
  • 命名路由 & 路由元信息 - 通过 name 导航,meta 携带自定义数据
  • TypeScript 类型提示 - 路由名称和路径自动补全与类型检查
  • uni API 拦截 - 可选拦截原生导航 API,统一守卫流程(interceptUniApi
  • 页面间通信 - useUniEventChannel 启用后所有导航方式均支持 eventChannel 双向通信,目标页通过 usePageChannel() 获取通道,基于 uni.$emit 全局事件总线,粘性缓存确保时序安全
  • 声明式导航 - RouterLink 组件,基于 uni navigator 封装,支持导航参数、动画、页面通信
  • 页面参数传递 - params 传递复杂数据,不暴露在 URL,支持 persistent 持久化
  • 查询参数增强 - queryInt() / queryNumber() / queryBool() 便捷解析
  • 导航动画 - push / replace / back 支持动画参数,仅 App 端生效
  • 路由状态同步 - syncRoute() 处理浏览器后退、物理返回键等场景
  • 错误处理 - 完整的 RouterError / NavigationFailure 体系,onError 全局捕获
  • 组合式 API - useRouter() / useRoute() / usePageChannel() 响应式访问路由与通信通道

安装

uni_modules(推荐)

mxuni-router 目录复制到项目的 uni_modules 目录下即可,无需 npm 安装。

npm

pnpm add @meng-xi/uni-router

npm 方式需将导入路径改为 @meng-xi/uni-router

快速开始

1. 创建路由器

// main.ts  
import { createSSRApp } from 'vue'  
import { createRouter } from './uni_modules/mxuni-router/js_sdk/index.js'  
import App from './App.vue'  

const router = createRouter({  
    routes: [  
        { path: 'pages/index/index', name: 'home', meta: { title: '首页' } },  
        { path: 'pages/about/about', name: 'about', meta: { title: '关于', requireAuth: true } }  
    ],  
    strict: true,  
    interceptUniApi: true, // 拦截 uni 原生导航 API,确保守卫生效  
    useUniEventChannel: true // 启用内置通信管理器,所有导航方式支持页面间双向通信  
})  

export function createApp() {  
    const app = createSSRApp(App)  
    app.use(router)  
    return { app }  
}

2. 路由导航

import { useRouter, useRoute } from './uni_modules/mxuni-router/js_sdk/index.js'  

const router = useRouter()  
const route = useRoute() // 返回响应式引用,路由变化时自动更新  

// 路径导航  
await router.push({ path: '/pages/about/about', query: { id: '1' } })  

// 命名导航  
await router.push({ name: 'about' })  

// 页面参数传递(params 不暴露在 URL,支持复杂数据)  
await router.push({ path: '/pages/detail/detail', params: { info: { name: 'Tom' } } })  

// 返回(执行完整守卫链)  
await router.back()

3. 页面间通信

启用 useUniEventChannel 后,所有导航方式均返回 eventChannel,目标页通过 usePageChannel() 获取通道:

// ===== 发起页 =====  
const result = await router.push({ path: '/pages/detail/detail' })  
result.eventChannel?.on('ready', data => console.log('目标页已就绪:', data))  
result.eventChannel?.emit('data', { msg: '发给目标页的数据' })  

// ===== 目标页(detail.vue)=====  
import { usePageChannel } from './uni_modules/mxuni-router/js_sdk/index.js'  

const channel = usePageChannel() // 无 __nav_id 时返回 noopChannel,无需判空  
channel.on('data', data => console.log('收到发起页数据:', data))  
channel.emit('ready', { status: 'ok' }) // 粘性缓存:发起页尚未注册 on 也能收到

4. 路由守卫

router.beforeEach((to, from, next) => {  
    if (to.meta.requireAuth && !isLoggedIn()) {  
        // 使用 replace 模式重定向,避免登录页之后残留受保护页面的历史  
        next({ name: 'login', query: { redirect: to.fullPath } }, { mode: 'replace' })  
    } else {  
        next()  
    }  
})

5. 自动生成路由配置(推荐)

配合 @meng-xi/vite-plugingenerateRouter 插件,可从 pages.json 自动生成路由配置和类型声明:

pnpm add @meng-xi/vite-plugin -D
// vite.config.ts  
import { defineConfig } from 'vite'  
import uni from '@dcloudio/vite-plugin-uni'  
import { generateRouter } from '@meng-xi/vite-plugin'  

export default defineConfig({  
    plugins: [  
        uni(),  
        generateRouter({  
            pagesJsonPath: 'src/pages.json',  
            outputPath: 'src/router.config.ts',  
            dts: true,  
            metaMapping: {  
                navigationBarTitleText: 'title',  
                requireAuth: 'requireAuth'  
            }  
        })  
    ]  
})

然后在 main.ts 中导入生成的路由配置:

import { createRouter } from './uni_modules/mxuni-router/js_sdk/index.js'  
import routes from './router.config'  

const router = createRouter({ routes })

文档

完整的 API 参考、配置项说明、RouterLink 组件属性、类型定义等请查阅官方网站:

📖 https://mengxi-studio.github.io/uni-router/

License

MIT

收起阅读 »

做AI给我做好了啊 ,傻逼玩意儿,开发者也是脑残

1.AI无法撤回到历史聊天记录

2.你们的AI只要一个项目,打开多个vue,会一起更改

3.你说你们有历史会话,但是他麻痹的会压缩,AI根本读不完

4.AI改了代码,不明确修改了哪里,我tm找了半天找到按钮,点击 接受 更改,哎你猜怎么着,无法接受,点了和没点一样,依然显示xxx行更改,

5.总结,你们tm要做AI给我做好了啊,基础的东西都没有,就en改啊

继续阅读 »

1.AI无法撤回到历史聊天记录

2.你们的AI只要一个项目,打开多个vue,会一起更改

3.你说你们有历史会话,但是他麻痹的会压缩,AI根本读不完

4.AI改了代码,不明确修改了哪里,我tm找了半天找到按钮,点击 接受 更改,哎你猜怎么着,无法接受,点了和没点一样,依然显示xxx行更改,

5.总结,你们tm要做AI给我做好了啊,基础的东西都没有,就en改啊

收起阅读 »

App Store 审核遇到 4.3(a) 怎么办?一次真实处理思路分享

可以,换平台发就不要和上一篇太像。下面这版标题、结构、开头都重新换了,关键词还是保留 苹果4.3(a)、App Store审核、马甲包上架、申诉,适合发 CSDN、知乎、掘金、百家号这类平台。

App Store 审核遇到 4.3(a) 怎么办?一次真实处理思路分享

做 iOS 上架的人,基本都绕不开苹果审核 4.3(a)。尤其是工具类、教育类、内容类、马甲包上架项目,只要 App 和已有产品相似度比较高,就有可能被苹果认为是重复应用。很多开发者收到 4.3(a) 后,第一反应是直接申诉,但实际处理下来,单靠申诉通常很难解决问题。

我更建议把 4.3(a) 当成一次“产品独立性检查”。也就是说,苹果不是只看你有没有换名字、换图标,而是看这个 App 是否真的有独立的功能、独立的内容、独立的用户场景。

  1. 4.3(a) 被拒,问题通常出在哪里?

苹果 4.3(a) 被拒,常见原因不是单点问题,而是多个相似点叠加造成的。

常见风险包括:

  1. App 功能和旧版本或同类产品太接近;
  2. 页面结构、首页布局、底部导航高度相似;
  3. App Store 截图、标题、描述、关键词重复;
  4. IPA 包里的资源文件、图片、模块命名相似;
  5. 只是换了 icon、启动图、主题色,没有改变核心体验;
  6. App 内还有旧项目名称、旧接口、旧隐私政策或旧文案。

很多时候,开发者觉得自己已经改了不少,但从审核人员视角看,可能还是同一个模板。

  1. 为什么直接申诉效果不好?

收到 4.3(a) 后,如果直接回复“我们的 App 是原创的,请重新审核”,通常说服力不够。因为苹果更关注 App 本身的实际变化,而不是开发者的口头解释。

如果 App 没有明显改动,截图没换,功能没变,描述还是原来的表达,那么即使申诉,也很容易继续被拒。

所以处理顺序应该是:

先找相似点,再做差异化,再写申诉说明,最后重新提交。

  1. 真正有效的处理方式是什么?

第一步,先改定位。
不要只把 App 描述成“工具”“学习软件”“生活服务”。要具体到目标人群和使用场景,比如儿童启蒙、考试练习、口语跟读、企业内部管理、个人效率记录等。定位清楚以后,审核备注和产品描述才有支撑。

第二步,改核心功能。
如果只是首页、分类、详情、会员、我的这几个页面来回套,很容易被认为模板化。可以调整功能入口、内容分类、任务流程、数据展示方式,让用户使用路径发生变化。

第三步,改 UI 和截图。
UI 不要只换颜色。首页结构、图标风格、按钮样式、卡片布局、空页面、引导页都应该重新设计。App Store 截图也要单独做,不能几个包共用一套模板。

第四步,清理资源和旧内容。
重点检查图片、音频、banner、课程、文章、接口路径、旧产品名称、旧客服信息、旧隐私政策链接。这些细节很容易让审核认为 App 是复制出来的。

第五步,检查 IPA 相似度。
如果是从旧项目改出来的,最好在提交前做一次包体检查,看看资源结构、模块命名、配置文件、无用代码是否还保留太多旧项目痕迹。

  1. 申诉应该怎么写?

4.3(a) 的申诉不要写得太硬,也不要说“我们没有问题”。更合适的写法是承认苹果的审核关注点,然后说明你已经完成了哪些调整。

可以这样写:

Hello App Review Team,
Thank you for your review.
We understand the concern regarding Guideline 4.3(a). After receiving the rejection, we carefully reviewed the app and made several updates to better reflect its independent value.
This app is designed for [目标用户] and focuses on [核心使用场景]. In this version, we updated the user interface, adjusted the feature structure, revised the App Store metadata, redesigned screenshots, and removed unrelated legacy content.
The app now provides a clearer user experience and independent functionality for its intended users.
We kindly ask you to review the updated version again. Thank you.

这类申诉的重点不是解释太多,而是让审核人员看到你已经针对问题做了实际调整。

  1. 重新提交前的检查清单

提交前建议逐项检查:

  1. App 名称、副标题、关键词是否独立;

  2. 描述是否围绕当前 App 重新写;

  3. 截图是否重新设计;

  4. 首页和核心页面是否有明显变化;

  5. 功能流程是否不是简单复制;

  6. 是否删除旧项目残留信息;

  7. 隐私政策和用户协议是否匹配;

  8. 权限申请是否合理;

  9. 是否存在空功能、假功能、不可用功能;

  10. IPA 包内资源和代码是否相似度过高。

  11. 总结

苹果审核 4.3(a) 并不是不能解决,但不能只靠一句申诉。真正有效的办法,是把 App 从产品定位、功能结构、UI 设计、资源内容、元数据文案、包体结构几个方面重新整理。

对于马甲包上架来说,最重要的一点是:不要让它看起来像复制包,而要让它成为一个有独立场景、独立功能、独立价值的 App。这样再配合清晰的申诉说明,重新提交通过的概率才会更高。

继续阅读 »

可以,换平台发就不要和上一篇太像。下面这版标题、结构、开头都重新换了,关键词还是保留 苹果4.3(a)、App Store审核、马甲包上架、申诉,适合发 CSDN、知乎、掘金、百家号这类平台。

App Store 审核遇到 4.3(a) 怎么办?一次真实处理思路分享

做 iOS 上架的人,基本都绕不开苹果审核 4.3(a)。尤其是工具类、教育类、内容类、马甲包上架项目,只要 App 和已有产品相似度比较高,就有可能被苹果认为是重复应用。很多开发者收到 4.3(a) 后,第一反应是直接申诉,但实际处理下来,单靠申诉通常很难解决问题。

我更建议把 4.3(a) 当成一次“产品独立性检查”。也就是说,苹果不是只看你有没有换名字、换图标,而是看这个 App 是否真的有独立的功能、独立的内容、独立的用户场景。

  1. 4.3(a) 被拒,问题通常出在哪里?

苹果 4.3(a) 被拒,常见原因不是单点问题,而是多个相似点叠加造成的。

常见风险包括:

  1. App 功能和旧版本或同类产品太接近;
  2. 页面结构、首页布局、底部导航高度相似;
  3. App Store 截图、标题、描述、关键词重复;
  4. IPA 包里的资源文件、图片、模块命名相似;
  5. 只是换了 icon、启动图、主题色,没有改变核心体验;
  6. App 内还有旧项目名称、旧接口、旧隐私政策或旧文案。

很多时候,开发者觉得自己已经改了不少,但从审核人员视角看,可能还是同一个模板。

  1. 为什么直接申诉效果不好?

收到 4.3(a) 后,如果直接回复“我们的 App 是原创的,请重新审核”,通常说服力不够。因为苹果更关注 App 本身的实际变化,而不是开发者的口头解释。

如果 App 没有明显改动,截图没换,功能没变,描述还是原来的表达,那么即使申诉,也很容易继续被拒。

所以处理顺序应该是:

先找相似点,再做差异化,再写申诉说明,最后重新提交。

  1. 真正有效的处理方式是什么?

第一步,先改定位。
不要只把 App 描述成“工具”“学习软件”“生活服务”。要具体到目标人群和使用场景,比如儿童启蒙、考试练习、口语跟读、企业内部管理、个人效率记录等。定位清楚以后,审核备注和产品描述才有支撑。

第二步,改核心功能。
如果只是首页、分类、详情、会员、我的这几个页面来回套,很容易被认为模板化。可以调整功能入口、内容分类、任务流程、数据展示方式,让用户使用路径发生变化。

第三步,改 UI 和截图。
UI 不要只换颜色。首页结构、图标风格、按钮样式、卡片布局、空页面、引导页都应该重新设计。App Store 截图也要单独做,不能几个包共用一套模板。

第四步,清理资源和旧内容。
重点检查图片、音频、banner、课程、文章、接口路径、旧产品名称、旧客服信息、旧隐私政策链接。这些细节很容易让审核认为 App 是复制出来的。

第五步,检查 IPA 相似度。
如果是从旧项目改出来的,最好在提交前做一次包体检查,看看资源结构、模块命名、配置文件、无用代码是否还保留太多旧项目痕迹。

  1. 申诉应该怎么写?

4.3(a) 的申诉不要写得太硬,也不要说“我们没有问题”。更合适的写法是承认苹果的审核关注点,然后说明你已经完成了哪些调整。

可以这样写:

Hello App Review Team,
Thank you for your review.
We understand the concern regarding Guideline 4.3(a). After receiving the rejection, we carefully reviewed the app and made several updates to better reflect its independent value.
This app is designed for [目标用户] and focuses on [核心使用场景]. In this version, we updated the user interface, adjusted the feature structure, revised the App Store metadata, redesigned screenshots, and removed unrelated legacy content.
The app now provides a clearer user experience and independent functionality for its intended users.
We kindly ask you to review the updated version again. Thank you.

这类申诉的重点不是解释太多,而是让审核人员看到你已经针对问题做了实际调整。

  1. 重新提交前的检查清单

提交前建议逐项检查:

  1. App 名称、副标题、关键词是否独立;

  2. 描述是否围绕当前 App 重新写;

  3. 截图是否重新设计;

  4. 首页和核心页面是否有明显变化;

  5. 功能流程是否不是简单复制;

  6. 是否删除旧项目残留信息;

  7. 隐私政策和用户协议是否匹配;

  8. 权限申请是否合理;

  9. 是否存在空功能、假功能、不可用功能;

  10. IPA 包内资源和代码是否相似度过高。

  11. 总结

苹果审核 4.3(a) 并不是不能解决,但不能只靠一句申诉。真正有效的办法,是把 App 从产品定位、功能结构、UI 设计、资源内容、元数据文案、包体结构几个方面重新整理。

对于马甲包上架来说,最重要的一点是:不要让它看起来像复制包,而要让它成为一个有独立场景、独立功能、独立价值的 App。这样再配合清晰的申诉说明,重新提交通过的概率才会更高。

收起阅读 »

Stack组件实现Swiper堆叠动画效果

问题现象
Swiper如何实现卡片堆叠样式:

上下堆叠:Swiper内容像卡片堆叠,在底部留部分空间显示下一页的内容,上下滑实现卡片切换。
左右堆叠:Swiper内容像卡片堆叠,在右侧留部分空间显示下一页的内容,左右滑实现卡片切换。
背景知识
Swiper组件提供滑动轮播显示的能力。Swiper本身是一个容器组件,当设置了多个子组件后,可以对这些子组件进行轮播显示。
Stack是堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
gesture可以为组件绑定手势方法进行相应处理,如滑动手势事件PanGesture。
animateTo指定由于闭包代码导致的状态变化插入过渡动效。
解决方案
上下堆叠实现。
自定义实现卡片堆叠的组件:使用Stack组件堆叠需要展示的图片,设置最上面的图片向上偏移部分距离,露出下一张图片的底部。为Stack绑定上下滑动的手势处理,实现切换图片逻辑,同时使用animateTo接口设置图片切换动画。

export class SwiperData {
imageSrc: Resource;

constructor(imageSrc: Resource) {
this.imageSrc = imageSrc;
}
}

@Component
export struct SwiperStackComponent {
@Link currentIndex: number;
@Prop swiperData: SwiperData[];
private halfCount: number = Math.floor(3 / 2);
private automaticSlidingDuration: number = 300;

aboutToAppear(): void {
this.currentIndex = 0;
}

// 修改堆叠方向系数计算
getImgCoefficients(index: number): number {
const coefficient = this.currentIndex - index;
const tempCoefficient = Math.abs(coefficient);
if (tempCoefficient <= this.halfCount) {
return coefficient;
}
const dataLength = this.swiperData.length;
let tempOffset = dataLength - tempCoefficient;
if (tempOffset <= this.halfCount) {
return coefficient > 0 ? -tempOffset : tempOffset;
}
return 0;
}

// 修改堆叠方向偏移量计算
getOffSet(index: number): number {
let offsetIndex = this.getImgCoefficients(index);
const tempOffset = Math.abs(offsetIndex);
let offset = 0;
if (tempOffset === 1) {
if (offsetIndex === 1) {
offsetIndex = -1;
}
offset = 50 * offsetIndex;
}
return -offset;
}

startAnimation(isLeft: boolean, duration: number): void {
this.getUIContext().animateTo({ duration: duration, }, () => {
const dataLength: number = this.swiperData.length;
const tempIndex: number = isLeft ? this.currentIndex + 1 : this.currentIndex - 1 + dataLength;
this.currentIndex = tempIndex % dataLength;
});
}

build() {
Stack() {
ForEach(this.swiperData, (item: SwiperData, index: number) => {
Stack({ alignContent: Alignment.Bottom }) {
Image(item.imageSrc)
.objectFit(ImageFit.Cover)
.width('100%')
.height('100%')
.borderRadius(8);
}
.offset({ x: 0, y: this.getOffSet(index) })
.shadow(ShadowStyle.OUTER_DEFAULT_SM)
.backgroundColor(Color.White)
.borderRadius(8)
.blur(index !== this.currentIndex ? 12 : 0)
// 通过animateTo实现动画并且同时改变currentIndex数据中间值来判断组件zIndex实现切换动画
.zIndex(index !== this.currentIndex && this.getImgCoefficients(index) === 0 ?
0 : 2 - Math.abs(this.getImgCoefficients(index)))
.width(310)
.height(index !== this.currentIndex ? 130 : 180);
});
}
.height(200)
.width('100%')
.gesture(
PanGesture({ direction: PanDirection.Vertical })
.onActionStart((event: GestureEvent) => {
this.startAnimation(event.offsetY < 0, this.automaticSlidingDuration);
})
)
.alignContent(Alignment.Center)
.padding({ left: 12, right: 12, top: 12 });
}
}
在页面中直接使用上面封装好的SwiperStackComponent即可,示例如下:传给SwiperStackComponent要堆叠的图片。
https://pastebin.com/m1LSXzRK
https://pastebin.com/cFaDz2JM
https://pastebin.com/94NrGTMh
https://pastebin.com/Yjx17LeK
https://pastebin.com/LqsPJ96h
https://pastebin.com/DPDgXMvK
https://pastebin.com/hSjsmXQA
https://pastebin.com/uKP1SMUS
https://pastebin.com/NzZpsC1T
https://pastebin.com/YYRMvbNK
https://pastebin.com/yMGLZhE6
https://pastebin.com/S95qV0Uz
https://pastebin.com/KkbjxT3u
https://pastebin.com/KtDaV8W6
https://pastebin.com/StWuCs6Y
https://pastebin.com/P1C46HUd
https://pastebin.com/jQVY68MF
https://pastebin.com/pZWdw2nr
https://pastebin.com/hWvq20CX
https://pastebin.com/6gYgutXU
https://pastebin.com/U4bchZ6m
https://pastebin.com/gfaWG0r6
https://pastebin.com/e9Y0r65R
https://pastebin.com/TVxKvWAq
https://pastebin.com/XQf3dgCp
https://pastebin.com/DpcrwpV5
https://pastebin.com/ebTwvrA8
https://pastebin.com/9AVaZHpP
https://pastebin.com/0XNziuPN
https://pastebin.com/5pX3w9Qz
https://pastebin.com/LxBeC4wT
https://pastebin.com/Ts4YH8YT
https://pastebin.com/gtTcZ7WL
https://pastebin.com/9hCAm4pk
https://pastebin.com/ivQAv3W6
https://pastebin.com/kQkScYnm
https://pastebin.com/Pggf2AJf
https://pastebin.com/93YQXuS2
https://pastebin.com/8bT7ebcm
https://pastebin.com/qhwZL1PA
https://pastebin.com/1j9Dfhf3
https://pastebin.com/yr8G62Eb
https://pastebin.com/i6keBveX
https://pastebin.com/8cShExkL
https://pastebin.com/uRpXa4D8
https://pastebin.com/GCWXMvkV
https://pastebin.com/5r8kkafj
https://pastebin.com/gZqmkKFY
https://pastebin.com/uzX4RXb8
https://pastebin.com/NX85Yeya
https://pastebin.com/0bnHmnn1
https://pastebin.com/4TEuJiyp
https://pastebin.com/19ECBLgF
https://pastebin.com/Q6sXfyLu
https://pastebin.com/J3wkaGhA
https://pastebin.com/MV4f7R1P
https://pastebin.com/4dtFguZU
https://pastebin.com/adNJrURC
https://pastebin.com/aTtEKzis
https://pastebin.com/PQrg1GWd
https://pastebin.com/gKTKwvqf
https://pastebin.com/uuYPPvaA
https://pastebin.com/j4Ls35Kc
https://pastebin.com/E0Ukv7Aj
https://pastebin.com/f6k4t5u2
https://pastebin.com/Q1DXAxWt
https://pastebin.com/tjfUhr1N
https://pastebin.com/uU5iHdYy
https://pastebin.com/cRR3KhUL
https://pastebin.com/nCiKrKtB
https://pastebin.com/dSHVsFy0
https://pastebin.com/2XAKUkn6
https://pastebin.com/Jppiihgb
https://pastebin.com/h3yaiqzz
https://pastebin.com/2JWDAsub
https://pastebin.com/tmPvc6uP
https://pastebin.com/FUnWQQwV
https://pastebin.com/Gp2UtxKN
https://pastebin.com/h95wHCfg
https://pastebin.com/fsCpD2Z8
https://pastebin.com/zJr9HCpS
https://pastebin.com/0PvFpNur
https://pastebin.com/VJyawuD5
https://pastebin.com/ba848eTS
https://pastebin.com/RACk8XWR
https://pastebin.com/0hwQHBAn
https://pastebin.com/sm0bEg5B
https://pastebin.com/KQVK1Ux4
https://pastebin.com/RzSuT9wU
https://pastebin.com/9zX0dafY
https://pastebin.com/vkitG9Jw
https://pastebin.com/BcsGM1ug
https://pastebin.com/mj2Ugnd4
https://pastebin.com/qUZmarS4
https://pastebin.com/db2sFPQt
https://pastebin.com/0Quw6jc1
https://pastebin.com/bPBJjv7K
https://pastebin.com/85VrwdEB
https://pastebin.com/ShwKYbhk
https://pastebin.com/n90Pae7n
https://pastebin.com/SKapsvXq
https://pastebin.com/jchhgXp5
https://pastebin.com/PKj7m3Lc
https://pastebin.com/uGYXHZAJ
https://pastebin.com/1Q4Smy2t
https://pastebin.com/sm9Guq40
https://pastebin.com/mwR9cXpE
https://pastebin.com/yJwCfxSP
https://pastebin.com/CBCVt6RG
https://pastebin.com/g5h9tUZ3
https://pastebin.com/LCgxSJzf
https://pastebin.com/VTQUWA8N
https://pastebin.com/qjDyTgv1
https://pastebin.com/6dFvv5Fp
https://pastebin.com/JaPKffGq
https://pastebin.com/92nW5dg4
https://pastebin.com/gH5hqPqi
https://pastebin.com/s6MKA67r
https://pastebin.com/8wtXs6PD
https://pastebin.com/jMc5xGpz
https://pastebin.com/EzDZD9aa
https://pastebin.com/p0AmhcjH
https://pastebin.com/QS1iAeCm
https://pastebin.com/X7QsHtdw
https://pastebin.com/0b4Y7fQY
https://pastebin.com/Y0sEGX9d
https://pastebin.com/6Vhw047x
https://pastebin.com/m7VxYsWv
https://pastebin.com/rDK9zsnw
https://pastebin.com/Z37U43eV
https://pastebin.com/80dR4QFi
https://pastebin.com/uB10GAXp
https://pastebin.com/8ts4FMmm
https://pastebin.com/y6TXLitK
https://pastebin.com/xPQ81CN6
https://pastebin.com/3hqhfZua
https://pastebin.com/aamUFtH2
https://pastebin.com/Lgh7nvP5
https://pastebin.com/x7Wg8naG
https://pastebin.com/aW7iLfRT
https://pastebin.com/Y7sTZ6Vb
https://pastebin.com/ZGPVkCwr
https://pastebin.com/jbcbQ9SV
https://pastebin.com/dxRWmQfk
https://pastebin.com/s02yGqxb
https://pastebin.com/1hB6AGkw
https://pastebin.com/hbcaCTpF
https://pastebin.com/pa2dcEuK
https://pastebin.com/2DV3gLRS
https://pastebin.com/wXieGb5z
https://pastebin.com/QDuKzm2f
https://pastebin.com/KzNj7grC
https://pastebin.com/89UWyNL0
https://pastebin.com/DGiiVVM6
https://pastebin.com/p1c3MvZT
https://pastebin.com/ecWTPGqn
https://pastebin.com/x6xBU9WV
https://pastebin.com/6yDL7fCa
https://pastebin.com/zjV0dLrr
https://pastebin.com/5d6FK30q
https://pastebin.com/EAxBa9Rm
https://pastebin.com/fwUrdJ4g
https://pastebin.com/VfBQU7Wb
https://pastebin.com/qwmVxX40
https://pastebin.com/71mdDTym
https://pastebin.com/qKrKiQbA
https://pastebin.com/z4WQJNkG
https://pastebin.com/1cdSJ8z5
https://pastebin.com/RtJXd9SW
https://pastebin.com/awkWi3s0
https://pastebin.com/xYkp2v8B
https://pastebin.com/rVehqExV
https://pastebin.com/Ws1Rd9bX
https://pastebin.com/8rXf1587
https://pastebin.com/9rfqNX50
https://pastebin.com/xVW5XQ2C
https://pastebin.com/dtHPSD6d
https://pastebin.com/mZD42AGm
https://pastebin.com/mXgU9d1f
https://pastebin.com/wTcD42mF
https://pastebin.com/KWqcG3if
https://pastebin.com/36p4EnHw
https://pastebin.com/TgjikqB4
https://pastebin.com/JHfBjWDg
https://pastebin.com/YhNpnZ3J
https://pastebin.com/TfC4Wa6F
https://pastebin.com/AFbL5S7E
https://pastebin.com/tVynY480
https://pastebin.com/bCevMY23
https://pastebin.com/7D3RhcvW
https://pastebin.com/sx5zBNRT
https://pastebin.com/6BEu5JtE
https://pastebin.com/LLdT59KZ
https://pastebin.com/qVaqen3E
https://pastebin.com/teqJ5Faw
https://pastebin.com/iYGt5cfB
https://pastebin.com/PvxNyjNd
https://pastebin.com/7LrBhZtK
https://pastebin.com/Uw6gnw98
https://pastebin.com/EiurXwH0
https://pastebin.com/jqRuvh0m
https://pastebin.com/geBdNDtb
https://pastebin.com/zQKdEZza
https://pastebin.com/QYFjE08P
https://pastebin.com/TBLAMRQF
https://pastebin.com/CzT8XHXy
https://pastebin.com/MBYQTUi5
https://pastebin.com/PCfCFgCR

继续阅读 »

问题现象
Swiper如何实现卡片堆叠样式:

上下堆叠:Swiper内容像卡片堆叠,在底部留部分空间显示下一页的内容,上下滑实现卡片切换。
左右堆叠:Swiper内容像卡片堆叠,在右侧留部分空间显示下一页的内容,左右滑实现卡片切换。
背景知识
Swiper组件提供滑动轮播显示的能力。Swiper本身是一个容器组件,当设置了多个子组件后,可以对这些子组件进行轮播显示。
Stack是堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
gesture可以为组件绑定手势方法进行相应处理,如滑动手势事件PanGesture。
animateTo指定由于闭包代码导致的状态变化插入过渡动效。
解决方案
上下堆叠实现。
自定义实现卡片堆叠的组件:使用Stack组件堆叠需要展示的图片,设置最上面的图片向上偏移部分距离,露出下一张图片的底部。为Stack绑定上下滑动的手势处理,实现切换图片逻辑,同时使用animateTo接口设置图片切换动画。

export class SwiperData {
imageSrc: Resource;

constructor(imageSrc: Resource) {
this.imageSrc = imageSrc;
}
}

@Component
export struct SwiperStackComponent {
@Link currentIndex: number;
@Prop swiperData: SwiperData[];
private halfCount: number = Math.floor(3 / 2);
private automaticSlidingDuration: number = 300;

aboutToAppear(): void {
this.currentIndex = 0;
}

// 修改堆叠方向系数计算
getImgCoefficients(index: number): number {
const coefficient = this.currentIndex - index;
const tempCoefficient = Math.abs(coefficient);
if (tempCoefficient <= this.halfCount) {
return coefficient;
}
const dataLength = this.swiperData.length;
let tempOffset = dataLength - tempCoefficient;
if (tempOffset <= this.halfCount) {
return coefficient > 0 ? -tempOffset : tempOffset;
}
return 0;
}

// 修改堆叠方向偏移量计算
getOffSet(index: number): number {
let offsetIndex = this.getImgCoefficients(index);
const tempOffset = Math.abs(offsetIndex);
let offset = 0;
if (tempOffset === 1) {
if (offsetIndex === 1) {
offsetIndex = -1;
}
offset = 50 * offsetIndex;
}
return -offset;
}

startAnimation(isLeft: boolean, duration: number): void {
this.getUIContext().animateTo({ duration: duration, }, () => {
const dataLength: number = this.swiperData.length;
const tempIndex: number = isLeft ? this.currentIndex + 1 : this.currentIndex - 1 + dataLength;
this.currentIndex = tempIndex % dataLength;
});
}

build() {
Stack() {
ForEach(this.swiperData, (item: SwiperData, index: number) => {
Stack({ alignContent: Alignment.Bottom }) {
Image(item.imageSrc)
.objectFit(ImageFit.Cover)
.width('100%')
.height('100%')
.borderRadius(8);
}
.offset({ x: 0, y: this.getOffSet(index) })
.shadow(ShadowStyle.OUTER_DEFAULT_SM)
.backgroundColor(Color.White)
.borderRadius(8)
.blur(index !== this.currentIndex ? 12 : 0)
// 通过animateTo实现动画并且同时改变currentIndex数据中间值来判断组件zIndex实现切换动画
.zIndex(index !== this.currentIndex && this.getImgCoefficients(index) === 0 ?
0 : 2 - Math.abs(this.getImgCoefficients(index)))
.width(310)
.height(index !== this.currentIndex ? 130 : 180);
});
}
.height(200)
.width('100%')
.gesture(
PanGesture({ direction: PanDirection.Vertical })
.onActionStart((event: GestureEvent) => {
this.startAnimation(event.offsetY < 0, this.automaticSlidingDuration);
})
)
.alignContent(Alignment.Center)
.padding({ left: 12, right: 12, top: 12 });
}
}
在页面中直接使用上面封装好的SwiperStackComponent即可,示例如下:传给SwiperStackComponent要堆叠的图片。
https://pastebin.com/m1LSXzRK
https://pastebin.com/cFaDz2JM
https://pastebin.com/94NrGTMh
https://pastebin.com/Yjx17LeK
https://pastebin.com/LqsPJ96h
https://pastebin.com/DPDgXMvK
https://pastebin.com/hSjsmXQA
https://pastebin.com/uKP1SMUS
https://pastebin.com/NzZpsC1T
https://pastebin.com/YYRMvbNK
https://pastebin.com/yMGLZhE6
https://pastebin.com/S95qV0Uz
https://pastebin.com/KkbjxT3u
https://pastebin.com/KtDaV8W6
https://pastebin.com/StWuCs6Y
https://pastebin.com/P1C46HUd
https://pastebin.com/jQVY68MF
https://pastebin.com/pZWdw2nr
https://pastebin.com/hWvq20CX
https://pastebin.com/6gYgutXU
https://pastebin.com/U4bchZ6m
https://pastebin.com/gfaWG0r6
https://pastebin.com/e9Y0r65R
https://pastebin.com/TVxKvWAq
https://pastebin.com/XQf3dgCp
https://pastebin.com/DpcrwpV5
https://pastebin.com/ebTwvrA8
https://pastebin.com/9AVaZHpP
https://pastebin.com/0XNziuPN
https://pastebin.com/5pX3w9Qz
https://pastebin.com/LxBeC4wT
https://pastebin.com/Ts4YH8YT
https://pastebin.com/gtTcZ7WL
https://pastebin.com/9hCAm4pk
https://pastebin.com/ivQAv3W6
https://pastebin.com/kQkScYnm
https://pastebin.com/Pggf2AJf
https://pastebin.com/93YQXuS2
https://pastebin.com/8bT7ebcm
https://pastebin.com/qhwZL1PA
https://pastebin.com/1j9Dfhf3
https://pastebin.com/yr8G62Eb
https://pastebin.com/i6keBveX
https://pastebin.com/8cShExkL
https://pastebin.com/uRpXa4D8
https://pastebin.com/GCWXMvkV
https://pastebin.com/5r8kkafj
https://pastebin.com/gZqmkKFY
https://pastebin.com/uzX4RXb8
https://pastebin.com/NX85Yeya
https://pastebin.com/0bnHmnn1
https://pastebin.com/4TEuJiyp
https://pastebin.com/19ECBLgF
https://pastebin.com/Q6sXfyLu
https://pastebin.com/J3wkaGhA
https://pastebin.com/MV4f7R1P
https://pastebin.com/4dtFguZU
https://pastebin.com/adNJrURC
https://pastebin.com/aTtEKzis
https://pastebin.com/PQrg1GWd
https://pastebin.com/gKTKwvqf
https://pastebin.com/uuYPPvaA
https://pastebin.com/j4Ls35Kc
https://pastebin.com/E0Ukv7Aj
https://pastebin.com/f6k4t5u2
https://pastebin.com/Q1DXAxWt
https://pastebin.com/tjfUhr1N
https://pastebin.com/uU5iHdYy
https://pastebin.com/cRR3KhUL
https://pastebin.com/nCiKrKtB
https://pastebin.com/dSHVsFy0
https://pastebin.com/2XAKUkn6
https://pastebin.com/Jppiihgb
https://pastebin.com/h3yaiqzz
https://pastebin.com/2JWDAsub
https://pastebin.com/tmPvc6uP
https://pastebin.com/FUnWQQwV
https://pastebin.com/Gp2UtxKN
https://pastebin.com/h95wHCfg
https://pastebin.com/fsCpD2Z8
https://pastebin.com/zJr9HCpS
https://pastebin.com/0PvFpNur
https://pastebin.com/VJyawuD5
https://pastebin.com/ba848eTS
https://pastebin.com/RACk8XWR
https://pastebin.com/0hwQHBAn
https://pastebin.com/sm0bEg5B
https://pastebin.com/KQVK1Ux4
https://pastebin.com/RzSuT9wU
https://pastebin.com/9zX0dafY
https://pastebin.com/vkitG9Jw
https://pastebin.com/BcsGM1ug
https://pastebin.com/mj2Ugnd4
https://pastebin.com/qUZmarS4
https://pastebin.com/db2sFPQt
https://pastebin.com/0Quw6jc1
https://pastebin.com/bPBJjv7K
https://pastebin.com/85VrwdEB
https://pastebin.com/ShwKYbhk
https://pastebin.com/n90Pae7n
https://pastebin.com/SKapsvXq
https://pastebin.com/jchhgXp5
https://pastebin.com/PKj7m3Lc
https://pastebin.com/uGYXHZAJ
https://pastebin.com/1Q4Smy2t
https://pastebin.com/sm9Guq40
https://pastebin.com/mwR9cXpE
https://pastebin.com/yJwCfxSP
https://pastebin.com/CBCVt6RG
https://pastebin.com/g5h9tUZ3
https://pastebin.com/LCgxSJzf
https://pastebin.com/VTQUWA8N
https://pastebin.com/qjDyTgv1
https://pastebin.com/6dFvv5Fp
https://pastebin.com/JaPKffGq
https://pastebin.com/92nW5dg4
https://pastebin.com/gH5hqPqi
https://pastebin.com/s6MKA67r
https://pastebin.com/8wtXs6PD
https://pastebin.com/jMc5xGpz
https://pastebin.com/EzDZD9aa
https://pastebin.com/p0AmhcjH
https://pastebin.com/QS1iAeCm
https://pastebin.com/X7QsHtdw
https://pastebin.com/0b4Y7fQY
https://pastebin.com/Y0sEGX9d
https://pastebin.com/6Vhw047x
https://pastebin.com/m7VxYsWv
https://pastebin.com/rDK9zsnw
https://pastebin.com/Z37U43eV
https://pastebin.com/80dR4QFi
https://pastebin.com/uB10GAXp
https://pastebin.com/8ts4FMmm
https://pastebin.com/y6TXLitK
https://pastebin.com/xPQ81CN6
https://pastebin.com/3hqhfZua
https://pastebin.com/aamUFtH2
https://pastebin.com/Lgh7nvP5
https://pastebin.com/x7Wg8naG
https://pastebin.com/aW7iLfRT
https://pastebin.com/Y7sTZ6Vb
https://pastebin.com/ZGPVkCwr
https://pastebin.com/jbcbQ9SV
https://pastebin.com/dxRWmQfk
https://pastebin.com/s02yGqxb
https://pastebin.com/1hB6AGkw
https://pastebin.com/hbcaCTpF
https://pastebin.com/pa2dcEuK
https://pastebin.com/2DV3gLRS
https://pastebin.com/wXieGb5z
https://pastebin.com/QDuKzm2f
https://pastebin.com/KzNj7grC
https://pastebin.com/89UWyNL0
https://pastebin.com/DGiiVVM6
https://pastebin.com/p1c3MvZT
https://pastebin.com/ecWTPGqn
https://pastebin.com/x6xBU9WV
https://pastebin.com/6yDL7fCa
https://pastebin.com/zjV0dLrr
https://pastebin.com/5d6FK30q
https://pastebin.com/EAxBa9Rm
https://pastebin.com/fwUrdJ4g
https://pastebin.com/VfBQU7Wb
https://pastebin.com/qwmVxX40
https://pastebin.com/71mdDTym
https://pastebin.com/qKrKiQbA
https://pastebin.com/z4WQJNkG
https://pastebin.com/1cdSJ8z5
https://pastebin.com/RtJXd9SW
https://pastebin.com/awkWi3s0
https://pastebin.com/xYkp2v8B
https://pastebin.com/rVehqExV
https://pastebin.com/Ws1Rd9bX
https://pastebin.com/8rXf1587
https://pastebin.com/9rfqNX50
https://pastebin.com/xVW5XQ2C
https://pastebin.com/dtHPSD6d
https://pastebin.com/mZD42AGm
https://pastebin.com/mXgU9d1f
https://pastebin.com/wTcD42mF
https://pastebin.com/KWqcG3if
https://pastebin.com/36p4EnHw
https://pastebin.com/TgjikqB4
https://pastebin.com/JHfBjWDg
https://pastebin.com/YhNpnZ3J
https://pastebin.com/TfC4Wa6F
https://pastebin.com/AFbL5S7E
https://pastebin.com/tVynY480
https://pastebin.com/bCevMY23
https://pastebin.com/7D3RhcvW
https://pastebin.com/sx5zBNRT
https://pastebin.com/6BEu5JtE
https://pastebin.com/LLdT59KZ
https://pastebin.com/qVaqen3E
https://pastebin.com/teqJ5Faw
https://pastebin.com/iYGt5cfB
https://pastebin.com/PvxNyjNd
https://pastebin.com/7LrBhZtK
https://pastebin.com/Uw6gnw98
https://pastebin.com/EiurXwH0
https://pastebin.com/jqRuvh0m
https://pastebin.com/geBdNDtb
https://pastebin.com/zQKdEZza
https://pastebin.com/QYFjE08P
https://pastebin.com/TBLAMRQF
https://pastebin.com/CzT8XHXy
https://pastebin.com/MBYQTUi5
https://pastebin.com/PCfCFgCR

收起阅读 »

关于 HBuilder X 更新 5.14版本 后无法编译【uni-app (x)项目编译插件正在启动中】问题的解决方案

HBuilderX升级 HBuilder X

更新后如果编译代码时出现下边的这种情况


先关闭HBuilder X,退出运行
然后点击桌面HBuilder X右键查看属性=》兼容性=》兼容模式 查看是否勾选,如下图

如果发现勾选了 取消勾选 然后点击右下角的应用;重启HBuilder X 查看问题是否已经解决;

根据官方说明,HBuilder X 5.11 及以上版本内置的 Node.js 已升级至 22.22.2,不再支持 Windows 8.1 及以下系统,因此要求运行环境必须为 Windows 8.1 或更高版本。
需要特别注意的是:如果您的电脑系统本身高于 Windows 8.1,但为 HBuilder X 勾选了“兼容模式”(例如兼容 Windows 7 或 8),HBuilder X 在运行时会强制模拟该低版本环境。这会导致内置的 Node.js 无法正常运行,进而引发编译卡死问题,具体表现为一直提示【uni-app (x)项目编译插件正在启动中】或报错“当前设备 Windows 版本低”。请取消兼容模式以确保正常运行。

继续阅读 »

更新后如果编译代码时出现下边的这种情况


先关闭HBuilder X,退出运行
然后点击桌面HBuilder X右键查看属性=》兼容性=》兼容模式 查看是否勾选,如下图

如果发现勾选了 取消勾选 然后点击右下角的应用;重启HBuilder X 查看问题是否已经解决;

根据官方说明,HBuilder X 5.11 及以上版本内置的 Node.js 已升级至 22.22.2,不再支持 Windows 8.1 及以下系统,因此要求运行环境必须为 Windows 8.1 或更高版本。
需要特别注意的是:如果您的电脑系统本身高于 Windows 8.1,但为 HBuilder X 勾选了“兼容模式”(例如兼容 Windows 7 或 8),HBuilder X 在运行时会强制模拟该低版本环境。这会导致内置的 Node.js 无法正常运行,进而引发编译卡死问题,具体表现为一直提示【uni-app (x)项目编译插件正在启动中】或报错“当前设备 Windows 版本低”。请取消兼容模式以确保正常运行。

收起阅读 »

uni-agent宇宙第一好用

服务器超级稳定,根本不会中断。
ai卡了中断了也没事,根本不会白白烧你的token。

服务器超级稳定,根本不会中断。
ai卡了中断了也没事,根本不会白白烧你的token。

通过自定义弹窗实现自定义样式的Toast

toast

问题现象
HarmonyOS的Toast接口,不支持设定圆角样式。如何实现类似其他平台的Toast样式?

效果预览
点击放大

背景知识
不依赖UI组件的全局自定义弹出框(openCustomDialog),适用于在相对应用复杂的场景来实现自定义弹出框,相较于CustomDialogController优势点在于页面解耦,支持动态刷新。
ArkUI提供轻量的UI元素复用机制@Builder,其内部UI结构固定,仅与使用方进行数据传递。可将重复使用的UI元素抽象成函数,在build函数中调用。
Text组件可以自定义展示文本框的UI样式,包括边框圆角、内边距等。
setTimeout接口支持设置一个定时器,该定时器在定时器到期后执行一个函数。
解决方案
如果需要实现类似其他平台的Toast样式,可借助自定义弹窗实现。

主要实现思路为,借助Text组件自定义类似其他平台Toast的UI样式,并封装为@Builder构建函数,将该函数传入ComponentContent创建弹窗对象,通过getUIContext开启该弹窗对象,开启后执行setTimeout,等待指定的时间后,执行关闭弹窗对象。详细步骤如下:

配置ToastContent组件属性并封装为@Builder构建函数。
@Component
struct ToastContent {
public text: string = '';
public clickText: string = '';
public clickListener = () => {
};
private textList: string[] = [];

aboutToAppear(): void {
if (this.clickText.length > 0) {
this.textList = this.text.split(this.clickText);
}
}

build() {
Column() {
if (this.clickText === '') {
Text(this.text).toastText();
} else {
Text() {
ForEach(this.textList, (item: string, num: number) => {
Span(item);
if (num < this.textList.length - 1) {
Span(this.clickText).fontColor(Color.Yellow);
}
});
}.onClick(this.clickListener).toastText();
}
}
.borderRadius(5)
.backgroundColor(Color.Black)
.padding(10)
.justifyContent(FlexAlign.SpaceBetween)
.margin({ left: '5%', right: '5%' });
}
}

// 封装Toast的@Builder方法
@Builder
function buildText(params: Params) {
ToastContent({ text: params.text, clickText: params.clickText, clickListener: params.clickListener });
}

// 封装公共样式
@Extend(Text)
function toastText() {
.fontSize(20)
.fontColor(Color.White);
}
创建Toast类,并创建构造方法与Toast实例方法。
/**

  • 封装全局蓝色浮动提示,支持点击
    */
    export class Toast {
    private toastParams: Params;

    constructor(text: string, time: number = 2000) {
    this.toastParams = new Params(text, time);
    }

    setClick(clickText: string, clickListener: () => void): Toast {
    this.toastParams.setClick(clickText, clickListener);
    return this;
    };

    async show() {
    let uiContext = AppStorage.get('currentUIContext') as UIContext;
    let click = this.toastParams.clickListener;
    let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), this.toastParams);
    uiContext.getPromptAction().openCustomDialog(contentNode, {
    showInSubWindow: this.toastParams.clickText === '' ? false : true,
    isModal: false,
    offset: { dx: 0, dy: '10%' }
    }).then(() => {
    setTimeout(() => {
    uiContext.getPromptAction().closeCustomDialog(contentNode);
    }, this.toastParams.time);
    });
    this.toastParams.clickListener = () => {
    click();
    uiContext.getPromptAction().closeCustomDialog(contentNode);
    };
    };
    }
    创建并弹出Toast,并且可以在Toast的setClick回调方法内实现点击Toast后的逻辑,如页面跳转。
    new Toast('点击Toast后屏幕将退出横屏,进入到竖屏状态', 3000).setClick('关闭自动添加', () => {
    this.windowClass.setPreferredOrientation(window.Orientation.PORTRAIT);
    this.pathStack.pushPathByName('DetailPage', null);
    }).show();
    完整示例参考如下:

Index.ets。
import { common } from '@kit.AbilityKit';
import { Toast } from './ToastContent';
import { window } from '@kit.ArkUI';

@Entry
@Component
struct Index {
pathStack: NavPathStack = new NavPathStack();
private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
private windowClass = (this.context as common.UIAbilityContext).windowStage.getMainWindowSync();

setOrientation(orientation: number) {
this.windowClass.setPreferredOrientation(orientation).then(() => {
}).catch(() => {
});
}

async aboutToAppear(): Promise<void> {
await this.windowClass.setPreferredOrientation(window.Orientation.LANDSCAPE);
AppStorage.setOrCreate('currentUIContext', this.getUIContext());
}

build() {
Navigation(this.pathStack) {
RelativeContainer() {
Column() {
Text('我的记录')
.fontSize(50)
.width('100%')
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bold)
Button('保存')
.onClick(() => {
new Toast('点击Toast后屏幕将退出横屏,进入到竖屏状态', 3000).setClick('关闭自动添加', () => {
this.windowClass.setPreferredOrientation(window.Orientation.PORTRAIT);
this.pathStack.pushPathByName('DetailPage', null);
}).show();
})
.backgroundColor(Color.Blue)
.fontColor(Color.White)
}
.alignRules({
center: { anchor: 'container', align: VerticalAlign.Center },
middle: { anchor: 'container', align: HorizontalAlign.Center }
})
}
.width('100%')
}
.mode(NavigationMode.Stack)
.height('100%')
.width('100%')
.height('100%')
.hideTitleBar(true)
}
}
https://pastebin.com/nwKPmmLF
https://pastebin.com/DwxhFWzG
https://pastebin.com/Jtg4RcM0
https://pastebin.com/7BvUaREN
https://pastebin.com/LGejrMwK
https://pastebin.com/V0qPwT9h
https://pastebin.com/tQzSevWd
https://pastebin.com/qncxPzug
https://pastebin.com/QNF651jK
https://pastebin.com/t3ZuR3CR
https://pastebin.com/H2PDqsEW
https://pastebin.com/Z7Wc9nic
https://pastebin.com/ECKtGAaJ
https://pastebin.com/EwXrd6qT
https://pastebin.com/HgYXSSrk
https://pastebin.com/uK3jyvu5
https://pastebin.com/vHzZdj9J
https://pastebin.com/sAMfi1Pz
https://pastebin.com/kVhLAgHT
https://pastebin.com/nkBEKJz4
https://pastebin.com/GrAvgxVg
https://pastebin.com/Umn0eUXt
https://pastebin.com/ut2dn5iH
https://pastebin.com/NgPFqHpy
https://pastebin.com/7e62WCL1
https://pastebin.com/wDM3tM66
https://pastebin.com/pwUhGKDv
https://pastebin.com/YvwB4xBj
https://pastebin.com/mzAxKZES
https://pastebin.com/NpnmdKf1
https://pastebin.com/C1FBURkc
https://pastebin.com/y0KsuZgB
https://pastebin.com/g7nDScSb
https://pastebin.com/7mDcGwtR
https://pastebin.com/3xV61sHt
https://pastebin.com/iQakPefn
https://pastebin.com/0CWW1Xta
https://pastebin.com/90zmcK10
https://pastebin.com/6CH0bCbh
https://pastebin.com/b6zdrzYw
https://pastebin.com/414XDcCa
https://pastebin.com/Mf0rTkWN
https://pastebin.com/gT4iprCN
https://pastebin.com/qeDfQegQ
https://pastebin.com/1e4vRx0y
https://pastebin.com/kGZUceQg
https://pastebin.com/9ustBt9n
https://pastebin.com/N4kwVZns
https://pastebin.com/qkBjMdA7
https://pastebin.com/w6XX4ciC
https://pastebin.com/54cBU8ze
https://pastebin.com/1mnAuUDZ
https://pastebin.com/VsgcjvTE
https://pastebin.com/wP31PyVb
https://pastebin.com/XPBk0zv8
https://pastebin.com/QRE1qguw
https://pastebin.com/iQpMss7p
https://pastebin.com/kKCXTdF9
https://pastebin.com/EwBniqXp
https://pastebin.com/A7LEwGq8
https://pastebin.com/XtXPS80z
https://pastebin.com/ghHSfqUZ
https://pastebin.com/pEH2u4Mj
https://pastebin.com/GiE2VShc
https://pastebin.com/NmfaPSX3
https://pastebin.com/fBfZs9d9
https://pastebin.com/CcHrZqng
https://pastebin.com/DcALJUNr
https://pastebin.com/hvGqEU4c
https://pastebin.com/HSf8h6BJ
https://pastebin.com/SCNykcCB
https://pastebin.com/RAnMDpBN
https://pastebin.com/0bbYFAG1
https://pastebin.com/6LjMvDuD
https://pastebin.com/u8dUE6wL
https://pastebin.com/8jVE6YLs
https://pastebin.com/xv6kzZyF
https://pastebin.com/L5WMJb5t
https://pastebin.com/sbe7FFD4
https://pastebin.com/aU4YUWDr
https://pastebin.com/3Z1YFmFW
https://pastebin.com/XvqqwSxq
https://pastebin.com/mJX0WRsc
https://pastebin.com/SGkjCXRB
https://pastebin.com/zv8zAxMd
https://pastebin.com/4bRTkCkm
https://pastebin.com/5s9JtWfS
https://pastebin.com/4VVU6Cxg
https://pastebin.com/TewUpi9F
https://pastebin.com/LKZwmBSi
https://pastebin.com/mu27p7w7
https://pastebin.com/JtiF4S2E
https://pastebin.com/xpeq692Q
https://pastebin.com/ypMqWqLC
https://pastebin.com/NrF7S04d
https://pastebin.com/j3riqEAh
https://pastebin.com/6iWCgpuJ
https://pastebin.com/s6KVgTgr
https://pastebin.com/1760APmp
https://pastebin.com/T6LTqjHK
https://pastebin.com/ttGrUAd7
https://pastebin.com/0PQTrPXK
https://pastebin.com/ZtmvtT35
https://pastebin.com/8TjBbUcR
https://pastebin.com/bYCv91Zb
https://pastebin.com/fpZrFF5w
https://pastebin.com/nrXWRsTd
https://pastebin.com/p4UWmpHz
https://pastebin.com/FUkFJhvg
https://pastebin.com/iBPFDUJ3
https://pastebin.com/ET0iD33D
https://pastebin.com/iwPwXsca
https://pastebin.com/8mmzg8p6
https://pastebin.com/8342WqK5
https://pastebin.com/pwYYMgbq
https://pastebin.com/cRgWPHH1
https://pastebin.com/rzyEfV9J
https://pastebin.com/kkAZWims
https://pastebin.com/fQn41cHZ
https://pastebin.com/fJ8vJ8be
https://pastebin.com/SzcAwdbu
https://pastebin.com/pCWkDayj
https://pastebin.com/L9pkse7j
https://pastebin.com/FxKwn5ng
https://pastebin.com/vFCLDqaV
https://pastebin.com/NRnYdnNH
https://pastebin.com/2ER3wSYv
https://pastebin.com/Q3YCRgG6
https://pastebin.com/YFaNTgNN
https://pastebin.com/9n9shZLu
https://pastebin.com/PBbWWUgX
https://pastebin.com/2R5pKJLh
https://pastebin.com/k2yY9ULe
https://pastebin.com/CJph4hrD
https://pastebin.com/6EwGM5CL
https://pastebin.com/DELYFAem
https://pastebin.com/Ggv8dLaa
https://pastebin.com/vM0r7xLq
https://pastebin.com/nbPGG85J
https://pastebin.com/ZVvYnFre
https://pastebin.com/LjJ9AwB9
https://pastebin.com/6hq2KXML
https://pastebin.com/pugZBcNi
https://pastebin.com/pmPvrW9q
https://pastebin.com/fhueU8S6
https://pastebin.com/kQazy17K
https://pastebin.com/VfTbduXf
https://pastebin.com/pXjYSwfd
https://pastebin.com/hUUnksFb
https://pastebin.com/AGnzrkpi
https://pastebin.com/s9jXdQ2e
https://pastebin.com/tkNdPSWm
https://pastebin.com/buGSwi0Q
https://pastebin.com/iqyy4wdi
https://pastebin.com/RiGF4W7H
https://pastebin.com/pxNKyFmV
https://pastebin.com/WwXY1ryk
https://pastebin.com/dNHDcvEE
https://pastebin.com/dstyKVbw
https://pastebin.com/recG0Tg4
https://pastebin.com/Bu8wxzkr
https://pastebin.com/FuZgbtXf
https://pastebin.com/56Ze2VPk
https://pastebin.com/qYG0243R
https://pastebin.com/AZ8iKJWf
https://pastebin.com/hNwShQks
https://pastebin.com/P8iaLhZF
https://pastebin.com/Dm05MGfE
https://pastebin.com/zamDMZgY
https://pastebin.com/7iyftr84
https://pastebin.com/0NssQJ78
https://pastebin.com/kdxr8s0Z
https://pastebin.com/awjDqW6h
https://pastebin.com/GWgZwDB6
https://pastebin.com/riTJWSts
https://pastebin.com/6dmkXAhN
https://pastebin.com/XZLHY1iX
https://pastebin.com/my97aREv
https://pastebin.com/H09exPyA
https://pastebin.com/Jjw8R1hF
https://pastebin.com/hm4qKthR
https://pastebin.com/G9uVUmcV
https://pastebin.com/Z4ZGXCbg
https://pastebin.com/zttcE8aT
https://pastebin.com/ieWfnuEy
https://pastebin.com/EnmdLmjw
https://pastebin.com/q7Nj4JEA
https://pastebin.com/cCnrQ8ft
https://pastebin.com/zt89NyCc
https://pastebin.com/cV5KJRUN
https://pastebin.com/e4pzjDm2
https://pastebin.com/rGb2fsmp
https://pastebin.com/q8ikYfF0
https://pastebin.com/y9e0KRNW
https://pastebin.com/r3qCSEu5
https://pastebin.com/H37KdV5m
https://pastebin.com/SREPy9Lr
https://pastebin.com/25JSeDYG
https://pastebin.com/j2a0BJdf
https://pastebin.com/pGbzGr3L
https://pastebin.com/1WJkKeyt
https://pastebin.com/DPDXbJ9L
https://pastebin.com/4gGEvFSt
https://pastebin.com/L0HCPVB0
https://pastebin.com/0eQjwvaY
https://pastebin.com/rzSNBFS8
https://pastebin.com/NWi9hui6
https://pastebin.com/xPjT5mxu
https://pastebin.com/e5neTg7h
https://pastebin.com/TZnwGHx4
https://pastebin.com/Tb98uyxA
https://pastebin.com/DPcVtW6C
https://pastebin.com/zZ7bNVBg
https://pastebin.com/yVQXZ1T1

继续阅读 »

问题现象
HarmonyOS的Toast接口,不支持设定圆角样式。如何实现类似其他平台的Toast样式?

效果预览
点击放大

背景知识
不依赖UI组件的全局自定义弹出框(openCustomDialog),适用于在相对应用复杂的场景来实现自定义弹出框,相较于CustomDialogController优势点在于页面解耦,支持动态刷新。
ArkUI提供轻量的UI元素复用机制@Builder,其内部UI结构固定,仅与使用方进行数据传递。可将重复使用的UI元素抽象成函数,在build函数中调用。
Text组件可以自定义展示文本框的UI样式,包括边框圆角、内边距等。
setTimeout接口支持设置一个定时器,该定时器在定时器到期后执行一个函数。
解决方案
如果需要实现类似其他平台的Toast样式,可借助自定义弹窗实现。

主要实现思路为,借助Text组件自定义类似其他平台Toast的UI样式,并封装为@Builder构建函数,将该函数传入ComponentContent创建弹窗对象,通过getUIContext开启该弹窗对象,开启后执行setTimeout,等待指定的时间后,执行关闭弹窗对象。详细步骤如下:

配置ToastContent组件属性并封装为@Builder构建函数。
@Component
struct ToastContent {
public text: string = '';
public clickText: string = '';
public clickListener = () => {
};
private textList: string[] = [];

aboutToAppear(): void {
if (this.clickText.length > 0) {
this.textList = this.text.split(this.clickText);
}
}

build() {
Column() {
if (this.clickText === '') {
Text(this.text).toastText();
} else {
Text() {
ForEach(this.textList, (item: string, num: number) => {
Span(item);
if (num < this.textList.length - 1) {
Span(this.clickText).fontColor(Color.Yellow);
}
});
}.onClick(this.clickListener).toastText();
}
}
.borderRadius(5)
.backgroundColor(Color.Black)
.padding(10)
.justifyContent(FlexAlign.SpaceBetween)
.margin({ left: '5%', right: '5%' });
}
}

// 封装Toast的@Builder方法
@Builder
function buildText(params: Params) {
ToastContent({ text: params.text, clickText: params.clickText, clickListener: params.clickListener });
}

// 封装公共样式
@Extend(Text)
function toastText() {
.fontSize(20)
.fontColor(Color.White);
}
创建Toast类,并创建构造方法与Toast实例方法。
/**

  • 封装全局蓝色浮动提示,支持点击
    */
    export class Toast {
    private toastParams: Params;

    constructor(text: string, time: number = 2000) {
    this.toastParams = new Params(text, time);
    }

    setClick(clickText: string, clickListener: () => void): Toast {
    this.toastParams.setClick(clickText, clickListener);
    return this;
    };

    async show() {
    let uiContext = AppStorage.get('currentUIContext') as UIContext;
    let click = this.toastParams.clickListener;
    let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), this.toastParams);
    uiContext.getPromptAction().openCustomDialog(contentNode, {
    showInSubWindow: this.toastParams.clickText === '' ? false : true,
    isModal: false,
    offset: { dx: 0, dy: '10%' }
    }).then(() => {
    setTimeout(() => {
    uiContext.getPromptAction().closeCustomDialog(contentNode);
    }, this.toastParams.time);
    });
    this.toastParams.clickListener = () => {
    click();
    uiContext.getPromptAction().closeCustomDialog(contentNode);
    };
    };
    }
    创建并弹出Toast,并且可以在Toast的setClick回调方法内实现点击Toast后的逻辑,如页面跳转。
    new Toast('点击Toast后屏幕将退出横屏,进入到竖屏状态', 3000).setClick('关闭自动添加', () => {
    this.windowClass.setPreferredOrientation(window.Orientation.PORTRAIT);
    this.pathStack.pushPathByName('DetailPage', null);
    }).show();
    完整示例参考如下:

Index.ets。
import { common } from '@kit.AbilityKit';
import { Toast } from './ToastContent';
import { window } from '@kit.ArkUI';

@Entry
@Component
struct Index {
pathStack: NavPathStack = new NavPathStack();
private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
private windowClass = (this.context as common.UIAbilityContext).windowStage.getMainWindowSync();

setOrientation(orientation: number) {
this.windowClass.setPreferredOrientation(orientation).then(() => {
}).catch(() => {
});
}

async aboutToAppear(): Promise<void> {
await this.windowClass.setPreferredOrientation(window.Orientation.LANDSCAPE);
AppStorage.setOrCreate('currentUIContext', this.getUIContext());
}

build() {
Navigation(this.pathStack) {
RelativeContainer() {
Column() {
Text('我的记录')
.fontSize(50)
.width('100%')
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bold)
Button('保存')
.onClick(() => {
new Toast('点击Toast后屏幕将退出横屏,进入到竖屏状态', 3000).setClick('关闭自动添加', () => {
this.windowClass.setPreferredOrientation(window.Orientation.PORTRAIT);
this.pathStack.pushPathByName('DetailPage', null);
}).show();
})
.backgroundColor(Color.Blue)
.fontColor(Color.White)
}
.alignRules({
center: { anchor: 'container', align: VerticalAlign.Center },
middle: { anchor: 'container', align: HorizontalAlign.Center }
})
}
.width('100%')
}
.mode(NavigationMode.Stack)
.height('100%')
.width('100%')
.height('100%')
.hideTitleBar(true)
}
}
https://pastebin.com/nwKPmmLF
https://pastebin.com/DwxhFWzG
https://pastebin.com/Jtg4RcM0
https://pastebin.com/7BvUaREN
https://pastebin.com/LGejrMwK
https://pastebin.com/V0qPwT9h
https://pastebin.com/tQzSevWd
https://pastebin.com/qncxPzug
https://pastebin.com/QNF651jK
https://pastebin.com/t3ZuR3CR
https://pastebin.com/H2PDqsEW
https://pastebin.com/Z7Wc9nic
https://pastebin.com/ECKtGAaJ
https://pastebin.com/EwXrd6qT
https://pastebin.com/HgYXSSrk
https://pastebin.com/uK3jyvu5
https://pastebin.com/vHzZdj9J
https://pastebin.com/sAMfi1Pz
https://pastebin.com/kVhLAgHT
https://pastebin.com/nkBEKJz4
https://pastebin.com/GrAvgxVg
https://pastebin.com/Umn0eUXt
https://pastebin.com/ut2dn5iH
https://pastebin.com/NgPFqHpy
https://pastebin.com/7e62WCL1
https://pastebin.com/wDM3tM66
https://pastebin.com/pwUhGKDv
https://pastebin.com/YvwB4xBj
https://pastebin.com/mzAxKZES
https://pastebin.com/NpnmdKf1
https://pastebin.com/C1FBURkc
https://pastebin.com/y0KsuZgB
https://pastebin.com/g7nDScSb
https://pastebin.com/7mDcGwtR
https://pastebin.com/3xV61sHt
https://pastebin.com/iQakPefn
https://pastebin.com/0CWW1Xta
https://pastebin.com/90zmcK10
https://pastebin.com/6CH0bCbh
https://pastebin.com/b6zdrzYw
https://pastebin.com/414XDcCa
https://pastebin.com/Mf0rTkWN
https://pastebin.com/gT4iprCN
https://pastebin.com/qeDfQegQ
https://pastebin.com/1e4vRx0y
https://pastebin.com/kGZUceQg
https://pastebin.com/9ustBt9n
https://pastebin.com/N4kwVZns
https://pastebin.com/qkBjMdA7
https://pastebin.com/w6XX4ciC
https://pastebin.com/54cBU8ze
https://pastebin.com/1mnAuUDZ
https://pastebin.com/VsgcjvTE
https://pastebin.com/wP31PyVb
https://pastebin.com/XPBk0zv8
https://pastebin.com/QRE1qguw
https://pastebin.com/iQpMss7p
https://pastebin.com/kKCXTdF9
https://pastebin.com/EwBniqXp
https://pastebin.com/A7LEwGq8
https://pastebin.com/XtXPS80z
https://pastebin.com/ghHSfqUZ
https://pastebin.com/pEH2u4Mj
https://pastebin.com/GiE2VShc
https://pastebin.com/NmfaPSX3
https://pastebin.com/fBfZs9d9
https://pastebin.com/CcHrZqng
https://pastebin.com/DcALJUNr
https://pastebin.com/hvGqEU4c
https://pastebin.com/HSf8h6BJ
https://pastebin.com/SCNykcCB
https://pastebin.com/RAnMDpBN
https://pastebin.com/0bbYFAG1
https://pastebin.com/6LjMvDuD
https://pastebin.com/u8dUE6wL
https://pastebin.com/8jVE6YLs
https://pastebin.com/xv6kzZyF
https://pastebin.com/L5WMJb5t
https://pastebin.com/sbe7FFD4
https://pastebin.com/aU4YUWDr
https://pastebin.com/3Z1YFmFW
https://pastebin.com/XvqqwSxq
https://pastebin.com/mJX0WRsc
https://pastebin.com/SGkjCXRB
https://pastebin.com/zv8zAxMd
https://pastebin.com/4bRTkCkm
https://pastebin.com/5s9JtWfS
https://pastebin.com/4VVU6Cxg
https://pastebin.com/TewUpi9F
https://pastebin.com/LKZwmBSi
https://pastebin.com/mu27p7w7
https://pastebin.com/JtiF4S2E
https://pastebin.com/xpeq692Q
https://pastebin.com/ypMqWqLC
https://pastebin.com/NrF7S04d
https://pastebin.com/j3riqEAh
https://pastebin.com/6iWCgpuJ
https://pastebin.com/s6KVgTgr
https://pastebin.com/1760APmp
https://pastebin.com/T6LTqjHK
https://pastebin.com/ttGrUAd7
https://pastebin.com/0PQTrPXK
https://pastebin.com/ZtmvtT35
https://pastebin.com/8TjBbUcR
https://pastebin.com/bYCv91Zb
https://pastebin.com/fpZrFF5w
https://pastebin.com/nrXWRsTd
https://pastebin.com/p4UWmpHz
https://pastebin.com/FUkFJhvg
https://pastebin.com/iBPFDUJ3
https://pastebin.com/ET0iD33D
https://pastebin.com/iwPwXsca
https://pastebin.com/8mmzg8p6
https://pastebin.com/8342WqK5
https://pastebin.com/pwYYMgbq
https://pastebin.com/cRgWPHH1
https://pastebin.com/rzyEfV9J
https://pastebin.com/kkAZWims
https://pastebin.com/fQn41cHZ
https://pastebin.com/fJ8vJ8be
https://pastebin.com/SzcAwdbu
https://pastebin.com/pCWkDayj
https://pastebin.com/L9pkse7j
https://pastebin.com/FxKwn5ng
https://pastebin.com/vFCLDqaV
https://pastebin.com/NRnYdnNH
https://pastebin.com/2ER3wSYv
https://pastebin.com/Q3YCRgG6
https://pastebin.com/YFaNTgNN
https://pastebin.com/9n9shZLu
https://pastebin.com/PBbWWUgX
https://pastebin.com/2R5pKJLh
https://pastebin.com/k2yY9ULe
https://pastebin.com/CJph4hrD
https://pastebin.com/6EwGM5CL
https://pastebin.com/DELYFAem
https://pastebin.com/Ggv8dLaa
https://pastebin.com/vM0r7xLq
https://pastebin.com/nbPGG85J
https://pastebin.com/ZVvYnFre
https://pastebin.com/LjJ9AwB9
https://pastebin.com/6hq2KXML
https://pastebin.com/pugZBcNi
https://pastebin.com/pmPvrW9q
https://pastebin.com/fhueU8S6
https://pastebin.com/kQazy17K
https://pastebin.com/VfTbduXf
https://pastebin.com/pXjYSwfd
https://pastebin.com/hUUnksFb
https://pastebin.com/AGnzrkpi
https://pastebin.com/s9jXdQ2e
https://pastebin.com/tkNdPSWm
https://pastebin.com/buGSwi0Q
https://pastebin.com/iqyy4wdi
https://pastebin.com/RiGF4W7H
https://pastebin.com/pxNKyFmV
https://pastebin.com/WwXY1ryk
https://pastebin.com/dNHDcvEE
https://pastebin.com/dstyKVbw
https://pastebin.com/recG0Tg4
https://pastebin.com/Bu8wxzkr
https://pastebin.com/FuZgbtXf
https://pastebin.com/56Ze2VPk
https://pastebin.com/qYG0243R
https://pastebin.com/AZ8iKJWf
https://pastebin.com/hNwShQks
https://pastebin.com/P8iaLhZF
https://pastebin.com/Dm05MGfE
https://pastebin.com/zamDMZgY
https://pastebin.com/7iyftr84
https://pastebin.com/0NssQJ78
https://pastebin.com/kdxr8s0Z
https://pastebin.com/awjDqW6h
https://pastebin.com/GWgZwDB6
https://pastebin.com/riTJWSts
https://pastebin.com/6dmkXAhN
https://pastebin.com/XZLHY1iX
https://pastebin.com/my97aREv
https://pastebin.com/H09exPyA
https://pastebin.com/Jjw8R1hF
https://pastebin.com/hm4qKthR
https://pastebin.com/G9uVUmcV
https://pastebin.com/Z4ZGXCbg
https://pastebin.com/zttcE8aT
https://pastebin.com/ieWfnuEy
https://pastebin.com/EnmdLmjw
https://pastebin.com/q7Nj4JEA
https://pastebin.com/cCnrQ8ft
https://pastebin.com/zt89NyCc
https://pastebin.com/cV5KJRUN
https://pastebin.com/e4pzjDm2
https://pastebin.com/rGb2fsmp
https://pastebin.com/q8ikYfF0
https://pastebin.com/y9e0KRNW
https://pastebin.com/r3qCSEu5
https://pastebin.com/H37KdV5m
https://pastebin.com/SREPy9Lr
https://pastebin.com/25JSeDYG
https://pastebin.com/j2a0BJdf
https://pastebin.com/pGbzGr3L
https://pastebin.com/1WJkKeyt
https://pastebin.com/DPDXbJ9L
https://pastebin.com/4gGEvFSt
https://pastebin.com/L0HCPVB0
https://pastebin.com/0eQjwvaY
https://pastebin.com/rzSNBFS8
https://pastebin.com/NWi9hui6
https://pastebin.com/xPjT5mxu
https://pastebin.com/e5neTg7h
https://pastebin.com/TZnwGHx4
https://pastebin.com/Tb98uyxA
https://pastebin.com/DPcVtW6C
https://pastebin.com/zZ7bNVBg
https://pastebin.com/yVQXZ1T1

收起阅读 »

Text组件字符超过特定长度时,超出部分如何隐藏与显示

text

问题现象
在Text中显示文本时,如果文本超过一定长度,通常会有超出部分隐藏与显示的需求,例如:当最多显示的行数为2,组件宽度比例为0.4时,该如何实现?

背景知识
measureText方法能够根据文本信息计算文本宽度。
getAllDisplays方法能够获取display对象,display对象的width属性为屏幕的宽度。
点击放大

解决方案
首先设定的文本长度计算方式:设定文本长度 = 屏幕宽度 最大行数 组件宽度比例。屏幕宽度可以使用getAllDisplays获取。
然后使用measureText方法测量实际文本宽度,比较“设定文本长度”与“实际文本宽度”进行大小比较,判断是否需要隐藏。
当需要隐藏时,只展示“设定长度”的文本内容,超出部分显示为“...”。当点击“…”时将该文本变为“…收起”,显示隐藏部分内容。
完整示例参考如下:

import { MeasureUtils } from '@kit.ArkUI';
import curves from '@ohos.curves';
import { BusinessError } from '@ohos.base';
import display from '@ohos.display';

@Entry
@Component
struct Index {
// 长文本
longMessage: string = '走在繁华的城市街头,明空感到无比紧张。他的心跳如雷鼓般擂动着胸膛,使得身上的伪装仿佛随时都要被揭开。然而,他仍然保持着冷静,凭借着过人的胆识与智慧,成功地躲过了敌人的层层封锁。\n' +
'\n' +
'  最终,明空来到了敌对帮派的老巢。此时此刻,那里的守卫正沉浸在欢庆的氛围中,丝毫没有察觉到即将来临的危机。明空深吸一口气,压抑住内心的激动,悄然潜入了这座古老的建筑。';
// 最大显示行数
@State lines: number = 2;
// 长文本状态(展开 or 收起)
@State collapseText: string = '...';
// 屏幕宽度(单位px)
screenWidth: number = 0;
// 是否需要显示"展开"字样(注:当文本长度较短时就不需要“展开”)
@State isExpanded: boolean = false;
uiContext: UIContext = this.getUIContext();
uiContextMeasure: MeasureUtils = this.uiContext.getMeasureUtils();
// 测量文本宽度(单位px)
textWidth: number = this.uiContextMeasure.measureText({
textContent: this.longMessage,
fontSize: 20
});
// 获取当前所有的display对象
promise: Promise<Array<display.Display>> = display.getAllDisplays();

aboutToAppear() {
console.info(文本宽度为:${this.textWidth});
this.promise.then((data: Array<display.Display>) => {
console.info(所有的屏幕信息:${JSON.stringify(data)});
// 单位为像素
this.screenWidth = data[0]["width"];
// 屏幕宽度 最大行数 组件宽度比例 和 文字测量宽度
this.isExpanded = this.screenWidth this.lines 0.4 <= this.textWidth;
}).catch((err: BusinessError) => {
console.error(Failed to obtain all the display objects. Code: ${JSON.stringify(err)});
});
}

build() {
Row() {
Column() {
if (this.isExpanded) {
Stack({ alignContent: Alignment.BottomEnd }) {
Text(this.longMessage)
.fontSize(20)
.fontColor(Color.Black)
.maxLines(this.lines)
.width("40%")
Row() {
Text(this.collapseText)
.fontSize(20)
.backgroundColor(Color.White)
}
.justifyContent(FlexAlign.End)
.onClick(() => {
if (this.collapseText == '...') {
this.collapseText = '...收起';
// 展开动画
this.uiContext.animateTo({
duration: 150,
curve: curves.springMotion(0.5, 0.8),
}, () => {
this.lines = -1; // 使得设置的最大行属性无效
});
} else {
this.collapseText = '...';
// 收起动画
this.uiContext.animateTo(
{
duration: 100,
curve: Curve.Friction,
}, () => {
this.lines = 2; // 只显示2行
});
}
})
}
}
else {
Text(this.longMessage)
.fontSize(20)
.fontColor(Color.Black)
}
}
.width('100%')
}
.height('100%')
}
}
https://pastebin.com/yYjzfBYh
https://pastebin.com/KvWVh2mC
https://pastebin.com/1e4eFFEG
https://pastebin.com/P3QEZ0Vt
https://pastebin.com/ySGX6wUJ
https://pastebin.com/jFJ9dwM8
https://pastebin.com/F8rBVMEp
https://pastebin.com/Th3G7tkh
https://pastebin.com/SN1eWG5Z
https://pastebin.com/eMtbaeZm
https://pastebin.com/7G7Ad9d5
https://pastebin.com/wAGuhNej
https://pastebin.com/Cmfya5mB
https://pastebin.com/pjPAkDdh
https://pastebin.com/C4124mFd
https://pastebin.com/1wHR87LD
https://pastebin.com/pccVzdhD
https://pastebin.com/J5MsUs86
https://pastebin.com/3DcWSqk8
https://pastebin.com/jFg0ThQC
https://pastebin.com/5xAUfgws
https://pastebin.com/6vaGRrFj
https://pastebin.com/jzHNkpVz
https://pastebin.com/6qZYe5TF
https://pastebin.com/QhC6D1Ea
https://pastebin.com/RHDyMM5i
https://pastebin.com/u6YdPYNT
https://pastebin.com/vMfTX3f8
https://pastebin.com/JfQ5h4mh
https://pastebin.com/eZTzxZXf
https://pastebin.com/ebALnXDi
https://pastebin.com/KgWVfrxD
https://pastebin.com/qN9C02WR
https://pastebin.com/wfmDCen7
https://pastebin.com/TRCTJxzH
https://pastebin.com/zUwZttGi
https://pastebin.com/tP3krksd
https://pastebin.com/a4zMuKAf
https://pastebin.com/Qd26iPzX
https://pastebin.com/QsYfKNGq
https://pastebin.com/ZBRQrP7g
https://pastebin.com/eLtxHFyq
https://pastebin.com/FFH804TB
https://pastebin.com/mpwpwtk1
https://pastebin.com/9MU20Mx1
https://pastebin.com/P8t51jjE
https://pastebin.com/yggX6dVr
https://pastebin.com/73KZ5Ewf
https://pastebin.com/B4s8zydV
https://pastebin.com/KvXBdDAh
https://pastebin.com/jfSidFKG
https://pastebin.com/i6z3pEGD
https://pastebin.com/K4wDCGB4
https://pastebin.com/Fk5vZKih
https://pastebin.com/j47NvPir
https://pastebin.com/r7jvjYg6
https://pastebin.com/BJzmiF4Q
https://pastebin.com/T983TDL4
https://pastebin.com/w03GsEzJ
https://pastebin.com/eVJ6DFrh
https://pastebin.com/JT5m4Fcd
https://pastebin.com/2Lyw6s6U
https://pastebin.com/nNnz4WSG
https://pastebin.com/zYw0vSEs
https://pastebin.com/7GNKsiA4
https://pastebin.com/1G8Ns8jL
https://pastebin.com/PfzWDnKs
https://pastebin.com/abuDWb37
https://pastebin.com/cV910k6U
https://pastebin.com/d1mmsxZD
https://pastebin.com/G9FgAyi3
https://pastebin.com/bAeBEub8
https://pastebin.com/1khz4e3X
https://pastebin.com/vxgkb5LD
https://pastebin.com/agcLMv2d
https://pastebin.com/nbSGyLLE
https://pastebin.com/fBXRb652
https://pastebin.com/AEaYhdxJ
https://pastebin.com/QnynP0t9
https://pastebin.com/KKG6w0k7
https://pastebin.com/s0iiVSxp
https://pastebin.com/EcmwFtbt
https://pastebin.com/KNmHDurJ
https://pastebin.com/CH32Naac
https://pastebin.com/DX2L75yh
https://pastebin.com/fkvZzYWa
https://pastebin.com/YH5AVbn3
https://pastebin.com/nkY9vSR2
https://pastebin.com/qQ9CkVRM
https://pastebin.com/cYMgDT9Q
https://pastebin.com/NCtDqJeU
https://pastebin.com/umbABgNV
https://pastebin.com/Jb0RrAxC
https://pastebin.com/nWHXx7p0
https://pastebin.com/Atbf7RdX
https://pastebin.com/yDd2FNsG
https://pastebin.com/NEfD7g3Z
https://pastebin.com/rZ1AkzAZ
https://pastebin.com/3HCfn9P1
https://pastebin.com/GWrtDxQr
https://pastebin.com/sf7fhcWs
https://pastebin.com/K7UL8AFj
https://pastebin.com/w4Hm6FuE
https://pastebin.com/5f0KTubZ
https://pastebin.com/6X5dsStC
https://pastebin.com/3nP0pK0t
https://pastebin.com/Emmq0RgR
https://pastebin.com/An3zQJse
https://pastebin.com/6h38FzmU
https://pastebin.com/y3GcsSec
https://pastebin.com/xnNtJTAg
https://pastebin.com/dZAGmXFz
https://pastebin.com/FZScNNPE
https://pastebin.com/8nLrkahp
https://pastebin.com/qx0Nznfz
https://pastebin.com/bbj21hbF
https://pastebin.com/QwZEg5QW
https://pastebin.com/A6Ph6wSg
https://pastebin.com/v8YbNB2J
https://pastebin.com/1Me85UF8
https://pastebin.com/N5zPTGhM
https://pastebin.com/cxR3Z0Q9
https://pastebin.com/yPptx6L2
https://pastebin.com/MgwpSDkL
https://pastebin.com/PdQkppe3
https://pastebin.com/ybfJNJTG
https://pastebin.com/4Cxexqf9
https://pastebin.com/cAShGPFD
https://pastebin.com/7iKLHyRr
https://pastebin.com/mttz0KMU
https://pastebin.com/EVrThu9E
https://pastebin.com/Y50asBDv
https://pastebin.com/95e2yHKf
https://pastebin.com/75zBX7Lg
https://pastebin.com/H88viQHj
https://pastebin.com/nJai6ZvU
https://pastebin.com/XGQr0J9c
https://pastebin.com/B26473RK
https://pastebin.com/ZkMRJwsT
https://pastebin.com/A7eaF21y
https://pastebin.com/qJrNz3u4
https://pastebin.com/2Egf1rmF
https://pastebin.com/ZDSc4Det
https://pastebin.com/DEGVVTgx
https://pastebin.com/MgRWq7xG
https://pastebin.com/qad7X0EQ
https://pastebin.com/G3xSFwem
https://pastebin.com/EffXNSx1
https://pastebin.com/e2GFCkaX
https://pastebin.com/d6XpErS5
https://pastebin.com/Atqhj6gz
https://pastebin.com/qmbXp0Sy
https://pastebin.com/UpgN3P4V
https://pastebin.com/VuwwY5ip
https://pastebin.com/NWnRfqPS
https://pastebin.com/c9GM9mBv
https://pastebin.com/0ZsBLMfd
https://pastebin.com/TFMs3tGt
https://pastebin.com/ehrjT1Gn
https://pastebin.com/m5RE6Avs
https://pastebin.com/fWYHdNgA
https://pastebin.com/gLVzuBx3
https://pastebin.com/rB9HYuaZ
https://pastebin.com/Fe2TBsvf
https://pastebin.com/xHugabcz
https://pastebin.com/ranMDSE7
https://pastebin.com/v1sqVnVc
https://pastebin.com/KB0TWNjm
https://pastebin.com/Z31VUeKU
https://pastebin.com/mjh7S1aF
https://pastebin.com/hrhppQs7
https://pastebin.com/gi9JXzNb
https://pastebin.com/fFVyxssb
https://pastebin.com/iBVj7uYr
https://pastebin.com/YvPJ8P5R
https://pastebin.com/70EAxttP
https://pastebin.com/EPbXeVtD
https://pastebin.com/EVSJNZin
https://pastebin.com/cc8QsGFx
https://pastebin.com/6TG7XnrV
https://pastebin.com/a84xV4uk
https://pastebin.com/KKZzVH4a
https://pastebin.com/XAMTJyHs
https://pastebin.com/Fz3DjJZ9
https://pastebin.com/g0sd0Bzs
https://pastebin.com/Jp8VpszT
https://pastebin.com/YUKEygx1
https://pastebin.com/uVwpBydg
https://pastebin.com/c9aAXgFc
https://pastebin.com/pZ28ZqPj
https://pastebin.com/rtW3W8AQ
https://pastebin.com/jg7cApH9
https://pastebin.com/JptcDPdH

继续阅读 »

问题现象
在Text中显示文本时,如果文本超过一定长度,通常会有超出部分隐藏与显示的需求,例如:当最多显示的行数为2,组件宽度比例为0.4时,该如何实现?

背景知识
measureText方法能够根据文本信息计算文本宽度。
getAllDisplays方法能够获取display对象,display对象的width属性为屏幕的宽度。
点击放大

解决方案
首先设定的文本长度计算方式:设定文本长度 = 屏幕宽度 最大行数 组件宽度比例。屏幕宽度可以使用getAllDisplays获取。
然后使用measureText方法测量实际文本宽度,比较“设定文本长度”与“实际文本宽度”进行大小比较,判断是否需要隐藏。
当需要隐藏时,只展示“设定长度”的文本内容,超出部分显示为“...”。当点击“…”时将该文本变为“…收起”,显示隐藏部分内容。
完整示例参考如下:

import { MeasureUtils } from '@kit.ArkUI';
import curves from '@ohos.curves';
import { BusinessError } from '@ohos.base';
import display from '@ohos.display';

@Entry
@Component
struct Index {
// 长文本
longMessage: string = '走在繁华的城市街头,明空感到无比紧张。他的心跳如雷鼓般擂动着胸膛,使得身上的伪装仿佛随时都要被揭开。然而,他仍然保持着冷静,凭借着过人的胆识与智慧,成功地躲过了敌人的层层封锁。\n' +
'\n' +
'  最终,明空来到了敌对帮派的老巢。此时此刻,那里的守卫正沉浸在欢庆的氛围中,丝毫没有察觉到即将来临的危机。明空深吸一口气,压抑住内心的激动,悄然潜入了这座古老的建筑。';
// 最大显示行数
@State lines: number = 2;
// 长文本状态(展开 or 收起)
@State collapseText: string = '...';
// 屏幕宽度(单位px)
screenWidth: number = 0;
// 是否需要显示"展开"字样(注:当文本长度较短时就不需要“展开”)
@State isExpanded: boolean = false;
uiContext: UIContext = this.getUIContext();
uiContextMeasure: MeasureUtils = this.uiContext.getMeasureUtils();
// 测量文本宽度(单位px)
textWidth: number = this.uiContextMeasure.measureText({
textContent: this.longMessage,
fontSize: 20
});
// 获取当前所有的display对象
promise: Promise<Array<display.Display>> = display.getAllDisplays();

aboutToAppear() {
console.info(文本宽度为:${this.textWidth});
this.promise.then((data: Array<display.Display>) => {
console.info(所有的屏幕信息:${JSON.stringify(data)});
// 单位为像素
this.screenWidth = data[0]["width"];
// 屏幕宽度 最大行数 组件宽度比例 和 文字测量宽度
this.isExpanded = this.screenWidth this.lines 0.4 <= this.textWidth;
}).catch((err: BusinessError) => {
console.error(Failed to obtain all the display objects. Code: ${JSON.stringify(err)});
});
}

build() {
Row() {
Column() {
if (this.isExpanded) {
Stack({ alignContent: Alignment.BottomEnd }) {
Text(this.longMessage)
.fontSize(20)
.fontColor(Color.Black)
.maxLines(this.lines)
.width("40%")
Row() {
Text(this.collapseText)
.fontSize(20)
.backgroundColor(Color.White)
}
.justifyContent(FlexAlign.End)
.onClick(() => {
if (this.collapseText == '...') {
this.collapseText = '...收起';
// 展开动画
this.uiContext.animateTo({
duration: 150,
curve: curves.springMotion(0.5, 0.8),
}, () => {
this.lines = -1; // 使得设置的最大行属性无效
});
} else {
this.collapseText = '...';
// 收起动画
this.uiContext.animateTo(
{
duration: 100,
curve: Curve.Friction,
}, () => {
this.lines = 2; // 只显示2行
});
}
})
}
}
else {
Text(this.longMessage)
.fontSize(20)
.fontColor(Color.Black)
}
}
.width('100%')
}
.height('100%')
}
}
https://pastebin.com/yYjzfBYh
https://pastebin.com/KvWVh2mC
https://pastebin.com/1e4eFFEG
https://pastebin.com/P3QEZ0Vt
https://pastebin.com/ySGX6wUJ
https://pastebin.com/jFJ9dwM8
https://pastebin.com/F8rBVMEp
https://pastebin.com/Th3G7tkh
https://pastebin.com/SN1eWG5Z
https://pastebin.com/eMtbaeZm
https://pastebin.com/7G7Ad9d5
https://pastebin.com/wAGuhNej
https://pastebin.com/Cmfya5mB
https://pastebin.com/pjPAkDdh
https://pastebin.com/C4124mFd
https://pastebin.com/1wHR87LD
https://pastebin.com/pccVzdhD
https://pastebin.com/J5MsUs86
https://pastebin.com/3DcWSqk8
https://pastebin.com/jFg0ThQC
https://pastebin.com/5xAUfgws
https://pastebin.com/6vaGRrFj
https://pastebin.com/jzHNkpVz
https://pastebin.com/6qZYe5TF
https://pastebin.com/QhC6D1Ea
https://pastebin.com/RHDyMM5i
https://pastebin.com/u6YdPYNT
https://pastebin.com/vMfTX3f8
https://pastebin.com/JfQ5h4mh
https://pastebin.com/eZTzxZXf
https://pastebin.com/ebALnXDi
https://pastebin.com/KgWVfrxD
https://pastebin.com/qN9C02WR
https://pastebin.com/wfmDCen7
https://pastebin.com/TRCTJxzH
https://pastebin.com/zUwZttGi
https://pastebin.com/tP3krksd
https://pastebin.com/a4zMuKAf
https://pastebin.com/Qd26iPzX
https://pastebin.com/QsYfKNGq
https://pastebin.com/ZBRQrP7g
https://pastebin.com/eLtxHFyq
https://pastebin.com/FFH804TB
https://pastebin.com/mpwpwtk1
https://pastebin.com/9MU20Mx1
https://pastebin.com/P8t51jjE
https://pastebin.com/yggX6dVr
https://pastebin.com/73KZ5Ewf
https://pastebin.com/B4s8zydV
https://pastebin.com/KvXBdDAh
https://pastebin.com/jfSidFKG
https://pastebin.com/i6z3pEGD
https://pastebin.com/K4wDCGB4
https://pastebin.com/Fk5vZKih
https://pastebin.com/j47NvPir
https://pastebin.com/r7jvjYg6
https://pastebin.com/BJzmiF4Q
https://pastebin.com/T983TDL4
https://pastebin.com/w03GsEzJ
https://pastebin.com/eVJ6DFrh
https://pastebin.com/JT5m4Fcd
https://pastebin.com/2Lyw6s6U
https://pastebin.com/nNnz4WSG
https://pastebin.com/zYw0vSEs
https://pastebin.com/7GNKsiA4
https://pastebin.com/1G8Ns8jL
https://pastebin.com/PfzWDnKs
https://pastebin.com/abuDWb37
https://pastebin.com/cV910k6U
https://pastebin.com/d1mmsxZD
https://pastebin.com/G9FgAyi3
https://pastebin.com/bAeBEub8
https://pastebin.com/1khz4e3X
https://pastebin.com/vxgkb5LD
https://pastebin.com/agcLMv2d
https://pastebin.com/nbSGyLLE
https://pastebin.com/fBXRb652
https://pastebin.com/AEaYhdxJ
https://pastebin.com/QnynP0t9
https://pastebin.com/KKG6w0k7
https://pastebin.com/s0iiVSxp
https://pastebin.com/EcmwFtbt
https://pastebin.com/KNmHDurJ
https://pastebin.com/CH32Naac
https://pastebin.com/DX2L75yh
https://pastebin.com/fkvZzYWa
https://pastebin.com/YH5AVbn3
https://pastebin.com/nkY9vSR2
https://pastebin.com/qQ9CkVRM
https://pastebin.com/cYMgDT9Q
https://pastebin.com/NCtDqJeU
https://pastebin.com/umbABgNV
https://pastebin.com/Jb0RrAxC
https://pastebin.com/nWHXx7p0
https://pastebin.com/Atbf7RdX
https://pastebin.com/yDd2FNsG
https://pastebin.com/NEfD7g3Z
https://pastebin.com/rZ1AkzAZ
https://pastebin.com/3HCfn9P1
https://pastebin.com/GWrtDxQr
https://pastebin.com/sf7fhcWs
https://pastebin.com/K7UL8AFj
https://pastebin.com/w4Hm6FuE
https://pastebin.com/5f0KTubZ
https://pastebin.com/6X5dsStC
https://pastebin.com/3nP0pK0t
https://pastebin.com/Emmq0RgR
https://pastebin.com/An3zQJse
https://pastebin.com/6h38FzmU
https://pastebin.com/y3GcsSec
https://pastebin.com/xnNtJTAg
https://pastebin.com/dZAGmXFz
https://pastebin.com/FZScNNPE
https://pastebin.com/8nLrkahp
https://pastebin.com/qx0Nznfz
https://pastebin.com/bbj21hbF
https://pastebin.com/QwZEg5QW
https://pastebin.com/A6Ph6wSg
https://pastebin.com/v8YbNB2J
https://pastebin.com/1Me85UF8
https://pastebin.com/N5zPTGhM
https://pastebin.com/cxR3Z0Q9
https://pastebin.com/yPptx6L2
https://pastebin.com/MgwpSDkL
https://pastebin.com/PdQkppe3
https://pastebin.com/ybfJNJTG
https://pastebin.com/4Cxexqf9
https://pastebin.com/cAShGPFD
https://pastebin.com/7iKLHyRr
https://pastebin.com/mttz0KMU
https://pastebin.com/EVrThu9E
https://pastebin.com/Y50asBDv
https://pastebin.com/95e2yHKf
https://pastebin.com/75zBX7Lg
https://pastebin.com/H88viQHj
https://pastebin.com/nJai6ZvU
https://pastebin.com/XGQr0J9c
https://pastebin.com/B26473RK
https://pastebin.com/ZkMRJwsT
https://pastebin.com/A7eaF21y
https://pastebin.com/qJrNz3u4
https://pastebin.com/2Egf1rmF
https://pastebin.com/ZDSc4Det
https://pastebin.com/DEGVVTgx
https://pastebin.com/MgRWq7xG
https://pastebin.com/qad7X0EQ
https://pastebin.com/G3xSFwem
https://pastebin.com/EffXNSx1
https://pastebin.com/e2GFCkaX
https://pastebin.com/d6XpErS5
https://pastebin.com/Atqhj6gz
https://pastebin.com/qmbXp0Sy
https://pastebin.com/UpgN3P4V
https://pastebin.com/VuwwY5ip
https://pastebin.com/NWnRfqPS
https://pastebin.com/c9GM9mBv
https://pastebin.com/0ZsBLMfd
https://pastebin.com/TFMs3tGt
https://pastebin.com/ehrjT1Gn
https://pastebin.com/m5RE6Avs
https://pastebin.com/fWYHdNgA
https://pastebin.com/gLVzuBx3
https://pastebin.com/rB9HYuaZ
https://pastebin.com/Fe2TBsvf
https://pastebin.com/xHugabcz
https://pastebin.com/ranMDSE7
https://pastebin.com/v1sqVnVc
https://pastebin.com/KB0TWNjm
https://pastebin.com/Z31VUeKU
https://pastebin.com/mjh7S1aF
https://pastebin.com/hrhppQs7
https://pastebin.com/gi9JXzNb
https://pastebin.com/fFVyxssb
https://pastebin.com/iBVj7uYr
https://pastebin.com/YvPJ8P5R
https://pastebin.com/70EAxttP
https://pastebin.com/EPbXeVtD
https://pastebin.com/EVSJNZin
https://pastebin.com/cc8QsGFx
https://pastebin.com/6TG7XnrV
https://pastebin.com/a84xV4uk
https://pastebin.com/KKZzVH4a
https://pastebin.com/XAMTJyHs
https://pastebin.com/Fz3DjJZ9
https://pastebin.com/g0sd0Bzs
https://pastebin.com/Jp8VpszT
https://pastebin.com/YUKEygx1
https://pastebin.com/uVwpBydg
https://pastebin.com/c9aAXgFc
https://pastebin.com/pZ28ZqPj
https://pastebin.com/rtW3W8AQ
https://pastebin.com/jg7cApH9
https://pastebin.com/JptcDPdH

收起阅读 »

如何解决NavDestination切换页面后浏览位置无法保存问题

问题现象
在HarmonyOS中,使用NavDestination实现页面跳转至其他页面后,下次进入如何保持跳转前页面的浏览位置?

背景知识
Navigation:Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(NavDestination的子组件)或非首页显示(NavDestination的子组件),首页和非首页通过路由进行切换。
@ohos.arkui.observer(无感监听)提供UI组件行为变化的无感监听能力。可以监听Navigation的页面切换事件进行相应操作。
Scroll是一种可滚动的容器组件,当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。
onDidScroll方法在Scroll滚动时触发,可用于在滑动过程中获取Scroll组件的偏移量yOffset。
scrollTo方法可用于让Scroll组件滑动到指定位置。
AppStorage是应用全局的UI状态存储,和应用的进程绑定,只能在UI主线程中使用,无法在子线程中使用、修改。
解决方案
方案一:使用路由模式保留页面实例。
在页面跳转时不要使用pop和clear等方法,否则NavDestination页面会被回收。可以采用单例模式MOVE_TO_TOP_SINGLETON跳转至指定的页面,该方式会使用栈内已存在的页面实例(即浏览位置不变)。

由于单例模式是从栈底到栈顶依次查找,当栈内存在多个同名页面实例时,会默认跳转最底层的同名页面实例,所以需确保栈内只存在一个同名实例,否则跳转的页面保留的滚动位置与上一次显示的页面会不一致(显示的是栈底同名实例保留的滚动位置)。
https://pastebin.com/jg7cApH9
https://pastebin.com/JptcDPdH
https://pastebin.com/fJ3FRPmU
https://pastebin.com/XW6K3fae
https://pastebin.com/LTuQfDs4
https://pastebin.com/B7u5aJgV
https://pastebin.com/kQDwTYr0
https://pastebin.com/xBwWHVWP
https://pastebin.com/XnbRLadK
https://pastebin.com/P7cJhcvz
https://pastebin.com/PPHJBRbF
https://pastebin.com/p3d9QNpd
https://pastebin.com/cvXpr2Xe
https://pastebin.com/xPFHs3J9
https://pastebin.com/jSmP0nAz
https://pastebin.com/F7BVe7rA
https://pastebin.com/rxxsw7rL
https://pastebin.com/dsapsf85
https://pastebin.com/WDTMjhBj
https://pastebin.com/YZm9PuQ0
https://pastebin.com/Ww8WiVCh
https://pastebin.com/1mdA2xYa
https://pastebin.com/HmnTgAvU
https://pastebin.com/4VFUyY1W
https://pastebin.com/iSCA3e1G
https://pastebin.com/DvvZgR5T
https://pastebin.com/XkCssDHN
https://pastebin.com/MS590bez
https://pastebin.com/APFd7Si7
https://pastebin.com/zszhKUha
https://pastebin.com/eCxbgYRD
https://pastebin.com/rvuEnH0U
https://pastebin.com/gvp8Sryc
https://pastebin.com/5G9bqXX8
https://pastebin.com/iveHA0B9
https://pastebin.com/YN31LHqg
https://pastebin.com/wwePXfTd
https://pastebin.com/xVjTy8Eh
https://pastebin.com/R2GZKWcL
https://pastebin.com/5R5n97MN
https://pastebin.com/bTJYZwXQ
https://pastebin.com/3MMSMF4w
https://pastebin.com/8FfWGCfV
https://pastebin.com/FG1V23qy
https://pastebin.com/R76515LN
https://pastebin.com/dgwf902E
https://pastebin.com/vF3LW9wz
https://pastebin.com/xuVFsSpN
https://pastebin.com/ycNDJLKt
https://pastebin.com/856Ss0AA
https://pastebin.com/SU4ZD1Zn
https://pastebin.com/VdiknXu9
https://pastebin.com/Qt1TYCpX
https://pastebin.com/7S5zwEmb
https://pastebin.com/YgNQiKJu
https://pastebin.com/8qE1cRZh
https://pastebin.com/qgtGNvG2
https://pastebin.com/ripQ1rCp
https://pastebin.com/vj9eK6Tw
https://pastebin.com/qD8waSpv
https://pastebin.com/LTPgDm4K
https://pastebin.com/AD1JQT8M
https://pastebin.com/F8BZKARC
https://pastebin.com/rtgxejCJ
https://pastebin.com/iGDCC7v6
https://pastebin.com/KDGz1ZAw
https://pastebin.com/T6ZRvjnv
https://pastebin.com/gn4VQL8C
https://pastebin.com/Pe2hxUPW
https://pastebin.com/ABUpdTBf
https://pastebin.com/hkr9q5qT
https://pastebin.com/7eMPsQSF
https://pastebin.com/2eazmQsj
https://pastebin.com/ZDyMcSUu
https://pastebin.com/40sqLNgD
https://pastebin.com/K4tB8zUq
https://pastebin.com/Vu5qGCNq
https://pastebin.com/NadrhJpP
https://pastebin.com/DMmxaYYg
https://pastebin.com/MD2QievW
https://pastebin.com/PE70Eqmr
https://pastebin.com/Ew5Fv07S
https://pastebin.com/UTUpEMDs
https://pastebin.com/msjPsKni
https://pastebin.com/Cy8PQ25K
https://pastebin.com/7mxb1JXt
https://pastebin.com/AgycmibL
https://pastebin.com/AVU1pR19
https://pastebin.com/3RmynMcG
https://pastebin.com/bAnvjLAq
https://pastebin.com/MNhKPjgL
https://pastebin.com/28gSRM4Y
https://pastebin.com/K10xjm2X
https://pastebin.com/HDW8s1cW
https://pastebin.com/Vz1hyR31
https://pastebin.com/0NVNEz8A
https://pastebin.com/5fqUpYWd
https://pastebin.com/L3Q0tjsz
https://pastebin.com/vcr11xWp
https://pastebin.com/QcuCqCyz
https://pastebin.com/VwCDdqGb
https://pastebin.com/RxyBYiQ1
https://pastebin.com/0cDzryZ8
https://pastebin.com/Ckxhy2mx
https://pastebin.com/y5gNKnjD
https://pastebin.com/k9cBDx1L
https://pastebin.com/KrdmLCzz
https://pastebin.com/XnbC31tF
https://pastebin.com/75Uq20MB
https://pastebin.com/w99f2xji
https://pastebin.com/wcbEE71j
https://pastebin.com/kGjYuVGW
https://pastebin.com/fugp0ttc
https://pastebin.com/N7s1QHRQ
https://pastebin.com/pPsWPb1a
https://pastebin.com/NWCppgZH
https://pastebin.com/sG0EpEW3
https://pastebin.com/QBXpHJhW
https://pastebin.com/9uaS9gT8
https://pastebin.com/q5RL1azA
https://pastebin.com/sXgTvvNe
https://pastebin.com/dM3Y0fNj
https://pastebin.com/2fvDixft
https://pastebin.com/TVCDt8Bk
https://pastebin.com/C5TNtJzS
https://pastebin.com/gvu7HrFG
https://pastebin.com/6gtmpefC
https://pastebin.com/e5XXTcSu
https://pastebin.com/ULRT40ic
https://pastebin.com/35dDdqDv
https://pastebin.com/V3Q4xPDB
https://pastebin.com/6FQ3hjhu
https://pastebin.com/GXVmSxWa
https://pastebin.com/ARpP5Sgx
https://pastebin.com/2C4G0GXm
https://pastebin.com/aydQrrL2
https://pastebin.com/RcDaQksi
https://pastebin.com/A09zVHhV
https://pastebin.com/EW4dKr6p
https://pastebin.com/NbuHg3jA
https://pastebin.com/mpvxPgsk
https://pastebin.com/d5me4T4d
https://pastebin.com/Pq4xqrwy
https://pastebin.com/1fwUEq5w
https://pastebin.com/RhQmmqpX
https://pastebin.com/0dmyxL0K
https://pastebin.com/whYZqr0q
https://pastebin.com/2Jzhd4hu
https://pastebin.com/kphAgh4R
https://pastebin.com/GDrrQdRp
https://pastebin.com/fY2yfAB7
https://pastebin.com/qYKKXLYL
https://pastebin.com/ybxMQCT1
https://pastebin.com/2au0x8Lf
https://pastebin.com/BvAZqhcP
https://pastebin.com/46LiCfhw
https://pastebin.com/DtZgXzmr
https://pastebin.com/XcWD26ZA
https://pastebin.com/C9emeaLS
https://pastebin.com/09GWiGur
https://pastebin.com/aH6FR1eC
https://pastebin.com/P8LJSBmN
https://pastebin.com/wiNqpWqX
https://pastebin.com/zT6vi5ys
https://pastebin.com/AVaKA8ci
https://pastebin.com/k3SrKPSD
https://pastebin.com/qtCMmq6p
https://pastebin.com/FJ464td4
https://pastebin.com/c6fkeh3w
https://pastebin.com/SbkLNL4E
https://pastebin.com/VGqk15nm
https://pastebin.com/h4SxwUdU
https://pastebin.com/Ngzb6uJq
https://pastebin.com/ff3aCBWh
https://pastebin.com/0i06Njsd
https://pastebin.com/fdYcqYTb
https://pastebin.com/bFiemuPx
https://pastebin.com/Syn6MvVa
https://pastebin.com/wGFSznjy
https://pastebin.com/StLnicTr
https://pastebin.com/KYLknUL1
https://pastebin.com/qKFitbxZ
https://pastebin.com/Q6tJT1ar
https://pastebin.com/GAyLPptG
https://pastebin.com/2zqFYn9X
https://pastebin.com/5ED0Vjjx
https://pastebin.com/dfPRkZay
https://pastebin.com/5W2xXc9L
https://pastebin.com/KRiFEcKH
https://pastebin.com/1kJv45DQ
https://pastebin.com/m2624v5Q
https://pastebin.com/w06qZAVW
https://pastebin.com/L4LmccPV
https://pastebin.com/JzNusi76
https://pastebin.com/EwSR48QA
https://pastebin.com/45A8NUsn
https://pastebin.com/TYg6awym
https://pastebin.com/ti8fjF4t
https://pastebin.com/eVVGSL2Z
https://pastebin.com/fRVbrzKS
https://pastebin.com/aVSd5N24
https://pastebin.com/tscNEGQe
https://pastebin.com/YWnRTD7n
https://pastebin.com/KWXg4hdG
https://pastebin.com/9phkHrjB
https://pastebin.com/3PtPqjvc
https://pastebin.com/8duhjkTw
https://pastebin.com/r2FdrSPY
https://pastebin.com/6fnVj3bj
https://pastebin.com/WsT72uPu

继续阅读 »

问题现象
在HarmonyOS中,使用NavDestination实现页面跳转至其他页面后,下次进入如何保持跳转前页面的浏览位置?

背景知识
Navigation:Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(NavDestination的子组件)或非首页显示(NavDestination的子组件),首页和非首页通过路由进行切换。
@ohos.arkui.observer(无感监听)提供UI组件行为变化的无感监听能力。可以监听Navigation的页面切换事件进行相应操作。
Scroll是一种可滚动的容器组件,当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。
onDidScroll方法在Scroll滚动时触发,可用于在滑动过程中获取Scroll组件的偏移量yOffset。
scrollTo方法可用于让Scroll组件滑动到指定位置。
AppStorage是应用全局的UI状态存储,和应用的进程绑定,只能在UI主线程中使用,无法在子线程中使用、修改。
解决方案
方案一:使用路由模式保留页面实例。
在页面跳转时不要使用pop和clear等方法,否则NavDestination页面会被回收。可以采用单例模式MOVE_TO_TOP_SINGLETON跳转至指定的页面,该方式会使用栈内已存在的页面实例(即浏览位置不变)。

由于单例模式是从栈底到栈顶依次查找,当栈内存在多个同名页面实例时,会默认跳转最底层的同名页面实例,所以需确保栈内只存在一个同名实例,否则跳转的页面保留的滚动位置与上一次显示的页面会不一致(显示的是栈底同名实例保留的滚动位置)。
https://pastebin.com/jg7cApH9
https://pastebin.com/JptcDPdH
https://pastebin.com/fJ3FRPmU
https://pastebin.com/XW6K3fae
https://pastebin.com/LTuQfDs4
https://pastebin.com/B7u5aJgV
https://pastebin.com/kQDwTYr0
https://pastebin.com/xBwWHVWP
https://pastebin.com/XnbRLadK
https://pastebin.com/P7cJhcvz
https://pastebin.com/PPHJBRbF
https://pastebin.com/p3d9QNpd
https://pastebin.com/cvXpr2Xe
https://pastebin.com/xPFHs3J9
https://pastebin.com/jSmP0nAz
https://pastebin.com/F7BVe7rA
https://pastebin.com/rxxsw7rL
https://pastebin.com/dsapsf85
https://pastebin.com/WDTMjhBj
https://pastebin.com/YZm9PuQ0
https://pastebin.com/Ww8WiVCh
https://pastebin.com/1mdA2xYa
https://pastebin.com/HmnTgAvU
https://pastebin.com/4VFUyY1W
https://pastebin.com/iSCA3e1G
https://pastebin.com/DvvZgR5T
https://pastebin.com/XkCssDHN
https://pastebin.com/MS590bez
https://pastebin.com/APFd7Si7
https://pastebin.com/zszhKUha
https://pastebin.com/eCxbgYRD
https://pastebin.com/rvuEnH0U
https://pastebin.com/gvp8Sryc
https://pastebin.com/5G9bqXX8
https://pastebin.com/iveHA0B9
https://pastebin.com/YN31LHqg
https://pastebin.com/wwePXfTd
https://pastebin.com/xVjTy8Eh
https://pastebin.com/R2GZKWcL
https://pastebin.com/5R5n97MN
https://pastebin.com/bTJYZwXQ
https://pastebin.com/3MMSMF4w
https://pastebin.com/8FfWGCfV
https://pastebin.com/FG1V23qy
https://pastebin.com/R76515LN
https://pastebin.com/dgwf902E
https://pastebin.com/vF3LW9wz
https://pastebin.com/xuVFsSpN
https://pastebin.com/ycNDJLKt
https://pastebin.com/856Ss0AA
https://pastebin.com/SU4ZD1Zn
https://pastebin.com/VdiknXu9
https://pastebin.com/Qt1TYCpX
https://pastebin.com/7S5zwEmb
https://pastebin.com/YgNQiKJu
https://pastebin.com/8qE1cRZh
https://pastebin.com/qgtGNvG2
https://pastebin.com/ripQ1rCp
https://pastebin.com/vj9eK6Tw
https://pastebin.com/qD8waSpv
https://pastebin.com/LTPgDm4K
https://pastebin.com/AD1JQT8M
https://pastebin.com/F8BZKARC
https://pastebin.com/rtgxejCJ
https://pastebin.com/iGDCC7v6
https://pastebin.com/KDGz1ZAw
https://pastebin.com/T6ZRvjnv
https://pastebin.com/gn4VQL8C
https://pastebin.com/Pe2hxUPW
https://pastebin.com/ABUpdTBf
https://pastebin.com/hkr9q5qT
https://pastebin.com/7eMPsQSF
https://pastebin.com/2eazmQsj
https://pastebin.com/ZDyMcSUu
https://pastebin.com/40sqLNgD
https://pastebin.com/K4tB8zUq
https://pastebin.com/Vu5qGCNq
https://pastebin.com/NadrhJpP
https://pastebin.com/DMmxaYYg
https://pastebin.com/MD2QievW
https://pastebin.com/PE70Eqmr
https://pastebin.com/Ew5Fv07S
https://pastebin.com/UTUpEMDs
https://pastebin.com/msjPsKni
https://pastebin.com/Cy8PQ25K
https://pastebin.com/7mxb1JXt
https://pastebin.com/AgycmibL
https://pastebin.com/AVU1pR19
https://pastebin.com/3RmynMcG
https://pastebin.com/bAnvjLAq
https://pastebin.com/MNhKPjgL
https://pastebin.com/28gSRM4Y
https://pastebin.com/K10xjm2X
https://pastebin.com/HDW8s1cW
https://pastebin.com/Vz1hyR31
https://pastebin.com/0NVNEz8A
https://pastebin.com/5fqUpYWd
https://pastebin.com/L3Q0tjsz
https://pastebin.com/vcr11xWp
https://pastebin.com/QcuCqCyz
https://pastebin.com/VwCDdqGb
https://pastebin.com/RxyBYiQ1
https://pastebin.com/0cDzryZ8
https://pastebin.com/Ckxhy2mx
https://pastebin.com/y5gNKnjD
https://pastebin.com/k9cBDx1L
https://pastebin.com/KrdmLCzz
https://pastebin.com/XnbC31tF
https://pastebin.com/75Uq20MB
https://pastebin.com/w99f2xji
https://pastebin.com/wcbEE71j
https://pastebin.com/kGjYuVGW
https://pastebin.com/fugp0ttc
https://pastebin.com/N7s1QHRQ
https://pastebin.com/pPsWPb1a
https://pastebin.com/NWCppgZH
https://pastebin.com/sG0EpEW3
https://pastebin.com/QBXpHJhW
https://pastebin.com/9uaS9gT8
https://pastebin.com/q5RL1azA
https://pastebin.com/sXgTvvNe
https://pastebin.com/dM3Y0fNj
https://pastebin.com/2fvDixft
https://pastebin.com/TVCDt8Bk
https://pastebin.com/C5TNtJzS
https://pastebin.com/gvu7HrFG
https://pastebin.com/6gtmpefC
https://pastebin.com/e5XXTcSu
https://pastebin.com/ULRT40ic
https://pastebin.com/35dDdqDv
https://pastebin.com/V3Q4xPDB
https://pastebin.com/6FQ3hjhu
https://pastebin.com/GXVmSxWa
https://pastebin.com/ARpP5Sgx
https://pastebin.com/2C4G0GXm
https://pastebin.com/aydQrrL2
https://pastebin.com/RcDaQksi
https://pastebin.com/A09zVHhV
https://pastebin.com/EW4dKr6p
https://pastebin.com/NbuHg3jA
https://pastebin.com/mpvxPgsk
https://pastebin.com/d5me4T4d
https://pastebin.com/Pq4xqrwy
https://pastebin.com/1fwUEq5w
https://pastebin.com/RhQmmqpX
https://pastebin.com/0dmyxL0K
https://pastebin.com/whYZqr0q
https://pastebin.com/2Jzhd4hu
https://pastebin.com/kphAgh4R
https://pastebin.com/GDrrQdRp
https://pastebin.com/fY2yfAB7
https://pastebin.com/qYKKXLYL
https://pastebin.com/ybxMQCT1
https://pastebin.com/2au0x8Lf
https://pastebin.com/BvAZqhcP
https://pastebin.com/46LiCfhw
https://pastebin.com/DtZgXzmr
https://pastebin.com/XcWD26ZA
https://pastebin.com/C9emeaLS
https://pastebin.com/09GWiGur
https://pastebin.com/aH6FR1eC
https://pastebin.com/P8LJSBmN
https://pastebin.com/wiNqpWqX
https://pastebin.com/zT6vi5ys
https://pastebin.com/AVaKA8ci
https://pastebin.com/k3SrKPSD
https://pastebin.com/qtCMmq6p
https://pastebin.com/FJ464td4
https://pastebin.com/c6fkeh3w
https://pastebin.com/SbkLNL4E
https://pastebin.com/VGqk15nm
https://pastebin.com/h4SxwUdU
https://pastebin.com/Ngzb6uJq
https://pastebin.com/ff3aCBWh
https://pastebin.com/0i06Njsd
https://pastebin.com/fdYcqYTb
https://pastebin.com/bFiemuPx
https://pastebin.com/Syn6MvVa
https://pastebin.com/wGFSznjy
https://pastebin.com/StLnicTr
https://pastebin.com/KYLknUL1
https://pastebin.com/qKFitbxZ
https://pastebin.com/Q6tJT1ar
https://pastebin.com/GAyLPptG
https://pastebin.com/2zqFYn9X
https://pastebin.com/5ED0Vjjx
https://pastebin.com/dfPRkZay
https://pastebin.com/5W2xXc9L
https://pastebin.com/KRiFEcKH
https://pastebin.com/1kJv45DQ
https://pastebin.com/m2624v5Q
https://pastebin.com/w06qZAVW
https://pastebin.com/L4LmccPV
https://pastebin.com/JzNusi76
https://pastebin.com/EwSR48QA
https://pastebin.com/45A8NUsn
https://pastebin.com/TYg6awym
https://pastebin.com/ti8fjF4t
https://pastebin.com/eVVGSL2Z
https://pastebin.com/fRVbrzKS
https://pastebin.com/aVSd5N24
https://pastebin.com/tscNEGQe
https://pastebin.com/YWnRTD7n
https://pastebin.com/KWXg4hdG
https://pastebin.com/9phkHrjB
https://pastebin.com/3PtPqjvc
https://pastebin.com/8duhjkTw
https://pastebin.com/r2FdrSPY
https://pastebin.com/6fnVj3bj
https://pastebin.com/WsT72uPu

收起阅读 »

华为应用市场上架被拒|2026最全高频驳回原因、整改方案与申诉攻略

华为应用市场

华为应用市场上架被拒|2026最全高频驳回原因、整改方案与申诉攻略
很多开发者iOS上架能过,却频频卡在华为应用市场审核。华为审核逻辑、合规标准、技术检测、内容风控和苹果完全不同,不看界面颜值,主打硬性合规、技术完整性、资质真实性、用户体验底线。
2026年华为应用市场审核全面升级,强化隐私合规扫描、SDK风控、资质核验、同质化检测、功能完整性校验,大量开发者遭遇反复驳回、版本打回、冻结提审权限等问题。
本文整理华为官方最新审核规则+上千款App上架实操经验,汇总TOP10高频被拒原因、逐点整改方案、提审避坑清单、专属申诉话术,工具、教育、娱乐、生活服务、企业类App通用,看完基本可以一次性过审。


一、先搞懂:华为审核和苹果审核的核心区别
很多人整改无效,根本原因是用iOS上架思维做华为上架,两套审核体系完全不同:

  • 苹果:重账号权重、代码指纹、同质化马甲、产品价值,轻度合规问题可容错;
  • 华为:零容错硬性合规,隐私、权限、资质、SDK、UX体验、加固兼容性任意一项不达标,直接驳回,无容错空间。
    华为审核最大特点:机器静态扫描+动态运行检测+人工资质复核三重校验,技术漏洞、合规瑕疵、资质造假100%检出。

二、2026华为上架TOP10高频被拒原因+精准整改方案(99%开发者踩坑)
1、隐私政策不合规(全网最高频驳回)
驳回表现:隐私协议缺失、链接打不开、未标注第三方SDK收集行为、权限用途说明模糊、未适配最新隐私规范。
核心坑点:华为严格检测所有集成的第三方SDK(推送、统计、登录、支付、定位),只要有SDK数据收集行为,隐私协议未逐条说明,直接驳回。同时禁止用户未同意隐私政策前初始化SDK、读取设备信息、偷跑流量。
标准整改方案:

  • 搭建独立可访问、无失效的隐私政策官网链接,页面干净无广告、无跳转;
  • 逐条写明:收集设备信息、相册、相机、定位、存储等权限的具体业务用途;
  • 单独公示所有第三方SDK名称、收集数据类型、使用用途、数据留存规则;
  • 代码拦截:用户未同意隐私前,禁止任何SDK初始化、网络请求、设备信息读取。
    2、权限申请过度、索权无依据
    驳回表现:申请通讯录、短信、电话、定位、后台权限,但App核心功能无需对应权限,属于违规过度索权。
    整改方案:
  • 删除所有非必要敏感权限,能不用就不用;
  • 保留的权限必须在隐私协议、弹窗说明中,明确对应核心业务场景,做到权限与功能强绑定;
  • 禁止静默申请权限,所有敏感权限必须用户主动授权后再启用对应功能。
    3、软著/资质主体不一致、材料不全
    驳回表现:软件著作权主体、开发者账号主体、企业营业执照主体不一致,软著截图模糊、版本不匹配、缺少授权证明。
    核心规则:华为审核资质100%严格匹配,主体不一致直接驳回,无协商余地。
    整改方案:
  • 软著主体必须和华为开发者账号企业主体完全一致;
  • 若为授权应用,补齐官方授权链路证明、多级授权文件;
  • 上传高清无水印、无遮挡资质材料,版本号与提交App版本完全对应。
    4、应用UX体验不达标、适配异常
    驳回表现:深色模式显示错乱、页面布局拉伸、按钮点击失效、分辨率适配异常、加载空白、交互卡顿,不符合华为UX体验标准。
    整改方案:
  • 全面适配华为手机常规分辨率、深色/浅色模式,无错乱、无遮挡、无黑屏;
  • 优化页面加载逻辑,杜绝首次启动空白、卡顿、长时间无响应;
  • 按钮、弹窗、输入框交互正常,无点击失效、穿透、错位问题。
    5、商店素材违规:截图/文案/图标虚假不符
    驳回表现:截图展示未上线功能、含有其他品牌机型、文案夸大宣传、关键词堆砌、素材含第三方水印、图文与实际功能不符。
    整改方案:
  • 所有截图、预览视频必须为App真实原生界面,禁止虚假展示、超前展示未开发功能;
  • 素材优先使用华为机型展示,去除其他品牌logo、水印;
  • 删除“100%有效”“最强”“极致”等绝对化宣传词汇,文案如实描述功能。
    6、测试残留、调试信息未清理
    驳回表现:包体内残留测试账号、测试弹窗、debug日志、测试水印、冗余调试代码,被判定为测试版本,不允许上架。
    整改方案:
  • 正式打包关闭Debug模式,清空所有测试日志、测试入口、测试弹窗;
  • 删除测试占位图、废弃页面、冗余资源,保证Release包纯净;
  • 杜绝包内残留内测、体验版标识。
    7、加固兼容问题、启动闪退、运行异常
    驳回表现:加固后Manifest解析失败、启动闪退、功能失效、防二次打包与华为系统签名冲突,审核机型无法正常运行。
    整改方案:
  • 关闭加固Manifest加密参数,避免配置文件无法解析;
  • 优化SDK和应用初始化时机,规避加固导致的初始化顺序错乱;
  • 上架前在华为主流机型实测运行,确保无闪退、崩溃、功能异常问题。
    8、同质化、低质应用判定
    驳回表现:模板套壳、功能简陋、与站内大量应用高度相似,无独立创新价值,判定低质应用驳回。
    整改方案:
  • 优化产品差异化,新增独立特色功能,杜绝纯模板套壳;
  • 重构页面布局、交互逻辑,与市面同类模板应用做出明显区分;
  • 完善功能闭环,避免单一简陋功能、无使用价值的工具应用。
    9、内容违规、敏感风控不通过
    驳回表现:包含涉政、色情、暴力、迷信、虚假金融、违规推广、侵权内容,或存在误导用户、恶意引流行为。
    整改方案:
  • 全面清理App内敏感文案、违规图片、第三方引流入口;
  • 教育、金融、医疗类应用补齐对应专项资质,无资质严禁展示相关服务内容;
  • 开启内容审核机制,杜绝UGC违规内容外露。
    10、鸿蒙适配不达标、API不规范
    驳回表现:使用私有API、未适配鸿蒙特性、分布式能力异常,系统兼容性不达标。
    整改方案:
  • 替换所有私有API,使用华为官方公开标准接口;
  • 通过DevEco Studio完成API兼容性检测,修复所有适配报错;
  • 针对鸿蒙机型完成基础适配,保证运行稳定、无功能异常。

三、华为上架必做自查清单(提审前一键核对)
按照以下清单核对,可规避95%驳回问题:

  1. 资质合规:软著、营业执照、授权文件主体一致、版本匹配、材料清晰完整;
  2. 隐私合规:隐私链接有效、SDK全部公示、权限用途明确、无前置偷跑数据;
  3. 权限精简:无多余敏感权限,权限与核心功能一一对应;
  4. 包体纯净:无Debug残留、无测试入口、无冗余调试信息;
  5. 体验适配:全机型适配、深色模式正常、无闪退卡顿、交互完整;
  6. 素材真实:图文文案与功能一致,无虚假宣传、无第三方违规元素;
  7. 内容干净:无敏感内容、无违规引流、无侵权素材;
  8. 加固兼容:加固后运行正常,无签名冲突、无解析失败。

四、华为审核被拒专属申诉话术(可直接复制)
华为审核支持人工复核,轻微误判、整改后可通过申诉快速过审,以下为通用标准话术:
尊敬的华为应用市场审核团队:
您好!针对本次应用审核驳回问题,我方已全面核对规则并完成全方位合规整改。
本次已完成整改内容如下:完整优化隐私政策公示内容,逐条标注第三方SDK数据收集规则与权限使用用途,清理全部测试残留代码与调试信息;精简非必要敏感权限,确保所有权限均与核心业务强相关;全面适配华为机型及深色模式,修复适配异常与交互问题;重做商店素材,保证图文与应用实际功能完全一致;排查并修复加固兼容问题,包体运行稳定无闪退。
本应用为合规自研产品,无同质化低质问题、无敏感违规内容、无侵权及虚假宣传行为,完全符合《华为应用市场审核指南》规范。
恳请审核团队重新复核审核,我方将严格遵守平台规则持续合规运营,感谢您的审核工作!


五、华为上架长期避坑核心逻辑
不同于苹果的权重风控,华为审核的核心是合规完整性+技术稳定性:

  • 不接受“差不多”,所有合规条款必须100%达标,无容错空间;
  • 资质、隐私、技术、素材、内容五大维度缺一不可,单一瑕疵直接驳回;
  • 杜绝模板套壳、虚假素材、过度索权、测试残留四大高频问题;
  • 每次提审前必须完整自查,避免反复驳回导致账号审核优先级降低。

六、全文总结
华为应用市场上架被拒,绝大多数不是玄学问题,而是隐私不合规、资质不匹配、技术适配瑕疵、素材虚假、权限滥用五大硬性问题导致。
2026年审核愈发严格,机器扫描全覆盖、人工复核零容忍,开发者必须摒弃敷衍整改思维,做到资质齐全、隐私合规、包体纯净、体验达标、素材真实。
严格按照本文自查清单整改、规范提审,即可大幅降低驳回率,实现华为应用市场一次性稳定上架。

继续阅读 »

华为应用市场上架被拒|2026最全高频驳回原因、整改方案与申诉攻略
很多开发者iOS上架能过,却频频卡在华为应用市场审核。华为审核逻辑、合规标准、技术检测、内容风控和苹果完全不同,不看界面颜值,主打硬性合规、技术完整性、资质真实性、用户体验底线。
2026年华为应用市场审核全面升级,强化隐私合规扫描、SDK风控、资质核验、同质化检测、功能完整性校验,大量开发者遭遇反复驳回、版本打回、冻结提审权限等问题。
本文整理华为官方最新审核规则+上千款App上架实操经验,汇总TOP10高频被拒原因、逐点整改方案、提审避坑清单、专属申诉话术,工具、教育、娱乐、生活服务、企业类App通用,看完基本可以一次性过审。


一、先搞懂:华为审核和苹果审核的核心区别
很多人整改无效,根本原因是用iOS上架思维做华为上架,两套审核体系完全不同:

  • 苹果:重账号权重、代码指纹、同质化马甲、产品价值,轻度合规问题可容错;
  • 华为:零容错硬性合规,隐私、权限、资质、SDK、UX体验、加固兼容性任意一项不达标,直接驳回,无容错空间。
    华为审核最大特点:机器静态扫描+动态运行检测+人工资质复核三重校验,技术漏洞、合规瑕疵、资质造假100%检出。

二、2026华为上架TOP10高频被拒原因+精准整改方案(99%开发者踩坑)
1、隐私政策不合规(全网最高频驳回)
驳回表现:隐私协议缺失、链接打不开、未标注第三方SDK收集行为、权限用途说明模糊、未适配最新隐私规范。
核心坑点:华为严格检测所有集成的第三方SDK(推送、统计、登录、支付、定位),只要有SDK数据收集行为,隐私协议未逐条说明,直接驳回。同时禁止用户未同意隐私政策前初始化SDK、读取设备信息、偷跑流量。
标准整改方案:

  • 搭建独立可访问、无失效的隐私政策官网链接,页面干净无广告、无跳转;
  • 逐条写明:收集设备信息、相册、相机、定位、存储等权限的具体业务用途;
  • 单独公示所有第三方SDK名称、收集数据类型、使用用途、数据留存规则;
  • 代码拦截:用户未同意隐私前,禁止任何SDK初始化、网络请求、设备信息读取。
    2、权限申请过度、索权无依据
    驳回表现:申请通讯录、短信、电话、定位、后台权限,但App核心功能无需对应权限,属于违规过度索权。
    整改方案:
  • 删除所有非必要敏感权限,能不用就不用;
  • 保留的权限必须在隐私协议、弹窗说明中,明确对应核心业务场景,做到权限与功能强绑定;
  • 禁止静默申请权限,所有敏感权限必须用户主动授权后再启用对应功能。
    3、软著/资质主体不一致、材料不全
    驳回表现:软件著作权主体、开发者账号主体、企业营业执照主体不一致,软著截图模糊、版本不匹配、缺少授权证明。
    核心规则:华为审核资质100%严格匹配,主体不一致直接驳回,无协商余地。
    整改方案:
  • 软著主体必须和华为开发者账号企业主体完全一致;
  • 若为授权应用,补齐官方授权链路证明、多级授权文件;
  • 上传高清无水印、无遮挡资质材料,版本号与提交App版本完全对应。
    4、应用UX体验不达标、适配异常
    驳回表现:深色模式显示错乱、页面布局拉伸、按钮点击失效、分辨率适配异常、加载空白、交互卡顿,不符合华为UX体验标准。
    整改方案:
  • 全面适配华为手机常规分辨率、深色/浅色模式,无错乱、无遮挡、无黑屏;
  • 优化页面加载逻辑,杜绝首次启动空白、卡顿、长时间无响应;
  • 按钮、弹窗、输入框交互正常,无点击失效、穿透、错位问题。
    5、商店素材违规:截图/文案/图标虚假不符
    驳回表现:截图展示未上线功能、含有其他品牌机型、文案夸大宣传、关键词堆砌、素材含第三方水印、图文与实际功能不符。
    整改方案:
  • 所有截图、预览视频必须为App真实原生界面,禁止虚假展示、超前展示未开发功能;
  • 素材优先使用华为机型展示,去除其他品牌logo、水印;
  • 删除“100%有效”“最强”“极致”等绝对化宣传词汇,文案如实描述功能。
    6、测试残留、调试信息未清理
    驳回表现:包体内残留测试账号、测试弹窗、debug日志、测试水印、冗余调试代码,被判定为测试版本,不允许上架。
    整改方案:
  • 正式打包关闭Debug模式,清空所有测试日志、测试入口、测试弹窗;
  • 删除测试占位图、废弃页面、冗余资源,保证Release包纯净;
  • 杜绝包内残留内测、体验版标识。
    7、加固兼容问题、启动闪退、运行异常
    驳回表现:加固后Manifest解析失败、启动闪退、功能失效、防二次打包与华为系统签名冲突,审核机型无法正常运行。
    整改方案:
  • 关闭加固Manifest加密参数,避免配置文件无法解析;
  • 优化SDK和应用初始化时机,规避加固导致的初始化顺序错乱;
  • 上架前在华为主流机型实测运行,确保无闪退、崩溃、功能异常问题。
    8、同质化、低质应用判定
    驳回表现:模板套壳、功能简陋、与站内大量应用高度相似,无独立创新价值,判定低质应用驳回。
    整改方案:
  • 优化产品差异化,新增独立特色功能,杜绝纯模板套壳;
  • 重构页面布局、交互逻辑,与市面同类模板应用做出明显区分;
  • 完善功能闭环,避免单一简陋功能、无使用价值的工具应用。
    9、内容违规、敏感风控不通过
    驳回表现:包含涉政、色情、暴力、迷信、虚假金融、违规推广、侵权内容,或存在误导用户、恶意引流行为。
    整改方案:
  • 全面清理App内敏感文案、违规图片、第三方引流入口;
  • 教育、金融、医疗类应用补齐对应专项资质,无资质严禁展示相关服务内容;
  • 开启内容审核机制,杜绝UGC违规内容外露。
    10、鸿蒙适配不达标、API不规范
    驳回表现:使用私有API、未适配鸿蒙特性、分布式能力异常,系统兼容性不达标。
    整改方案:
  • 替换所有私有API,使用华为官方公开标准接口;
  • 通过DevEco Studio完成API兼容性检测,修复所有适配报错;
  • 针对鸿蒙机型完成基础适配,保证运行稳定、无功能异常。

三、华为上架必做自查清单(提审前一键核对)
按照以下清单核对,可规避95%驳回问题:

  1. 资质合规:软著、营业执照、授权文件主体一致、版本匹配、材料清晰完整;
  2. 隐私合规:隐私链接有效、SDK全部公示、权限用途明确、无前置偷跑数据;
  3. 权限精简:无多余敏感权限,权限与核心功能一一对应;
  4. 包体纯净:无Debug残留、无测试入口、无冗余调试信息;
  5. 体验适配:全机型适配、深色模式正常、无闪退卡顿、交互完整;
  6. 素材真实:图文文案与功能一致,无虚假宣传、无第三方违规元素;
  7. 内容干净:无敏感内容、无违规引流、无侵权素材;
  8. 加固兼容:加固后运行正常,无签名冲突、无解析失败。

四、华为审核被拒专属申诉话术(可直接复制)
华为审核支持人工复核,轻微误判、整改后可通过申诉快速过审,以下为通用标准话术:
尊敬的华为应用市场审核团队:
您好!针对本次应用审核驳回问题,我方已全面核对规则并完成全方位合规整改。
本次已完成整改内容如下:完整优化隐私政策公示内容,逐条标注第三方SDK数据收集规则与权限使用用途,清理全部测试残留代码与调试信息;精简非必要敏感权限,确保所有权限均与核心业务强相关;全面适配华为机型及深色模式,修复适配异常与交互问题;重做商店素材,保证图文与应用实际功能完全一致;排查并修复加固兼容问题,包体运行稳定无闪退。
本应用为合规自研产品,无同质化低质问题、无敏感违规内容、无侵权及虚假宣传行为,完全符合《华为应用市场审核指南》规范。
恳请审核团队重新复核审核,我方将严格遵守平台规则持续合规运营,感谢您的审核工作!


五、华为上架长期避坑核心逻辑
不同于苹果的权重风控,华为审核的核心是合规完整性+技术稳定性:

  • 不接受“差不多”,所有合规条款必须100%达标,无容错空间;
  • 资质、隐私、技术、素材、内容五大维度缺一不可,单一瑕疵直接驳回;
  • 杜绝模板套壳、虚假素材、过度索权、测试残留四大高频问题;
  • 每次提审前必须完整自查,避免反复驳回导致账号审核优先级降低。

六、全文总结
华为应用市场上架被拒,绝大多数不是玄学问题,而是隐私不合规、资质不匹配、技术适配瑕疵、素材虚假、权限滥用五大硬性问题导致。
2026年审核愈发严格,机器扫描全覆盖、人工复核零容忍,开发者必须摒弃敷衍整改思维,做到资质齐全、隐私合规、包体纯净、体验达标、素材真实。
严格按照本文自查清单整改、规范提审,即可大幅降低驳回率,实现华为应用市场一次性稳定上架。

收起阅读 »

苹果上架遇到 3.2 封号怎么办?原因是什么?应该怎么申诉?

苹果审核

苹果上架遇到 3.2 封号怎么办?原因是什么?应该怎么申诉?

在 App Store 上架过程中,很多开发者最怕遇到两类问题:一种是 App 被拒,另一种就是开发者账号被调查甚至被封。相比普通拒审,3.2 相关问题往往更麻烦,因为它不只是某个版本的问题,还可能涉及账号主体、业务模式、资质材料、开发者身份、商业合规等多个方面。

很多人看到 3.2 后第一反应是:“是不是 App 有问题?”其实不一定。3.2 更偏向商业模式、开发者身份、资质真实性、业务合规性、是否存在误导用户、是否存在代上架或批量上架等问题。如果处理不当,轻则 App 被拒,重则账号被限制、调查,甚至终止开发者计划。

一、苹果 3.2 主要看什么?

苹果审核指南 3.2 属于“Business”商业相关规则,重点关注 App 的商业模式是否合理、开发者身份是否真实、服务是否合规、是否存在误导用户或不符合平台规则的行为。

简单理解,苹果会关注以下几个问题:

  1. 这个 App 的业务是否真实存在;
  2. 开发者是否有资格提供这个服务;
  3. App 是否涉及需要资质的行业;
  4. App 是否存在误导用户的商业行为;
  5. App 是否是给别人代上架;
  6. 账号主体和 App 业务是否匹配;
  7. 是否存在批量提交、重复提交、规避审核的行为;
  8. 是否存在虚假资料、虚假功能、虚假宣传;
  9. 是否存在高风险业务,比如金融、医疗、借贷、博彩、虚拟资产等;
  10. 是否违反了 Apple Developer Program License Agreement。

所以,3.2 不是简单改几句文案就一定能解决的问题。它通常需要从账号、资质、业务、App 内容、审核说明多个方面一起处理。

二、为什么 3.2 会导致封号?

普通拒审一般只影响当前版本,但 3.2 如果严重,就可能影响整个开发者账号。

原因很简单:苹果可能认为问题不是 App 的某个页面,而是账号本身存在风险。比如开发者账号和实际业务不匹配、提交的 App 不属于账号主体经营范围、存在代上架嫌疑、重复提交高风险应用、使用虚假资料、绕过审核规则等。

一旦苹果认为账号存在信任问题,就可能不只是拒绝 App,而是对账号进行进一步审核。这个时候开发者可能会收到类似账号调查、账号终止、开发者计划被移除等邮件。

常见表现包括:

  1. App 审核中突然被拒;
  2. App Store Connect 功能受限;
  3. 新版本无法继续提交;
  4. 账号收到调查邮件;
  5. 账号被要求提供业务资质;
  6. 账号被要求解释 App 归属;
  7. 账号被终止开发者计划;
  8. 同主体或相关账号后续提交变得更难。

所以,遇到 3.2 不要简单当作普通拒审处理,更不要频繁重复提交。

三、3.2 封号常见原因

  1. 账号主体和 App 业务不匹配

这是非常常见的原因。

比如账号主体是一家普通科技公司,但提交的 App 是金融、借贷、医疗、保险、证券、心理咨询、算命、支付、数字藏品、虚拟资产等业务。苹果可能会要求证明你有资格提供这些服务。

如果主体资料、营业执照经营范围、网站备案、隐私政策、App 内品牌、客服信息、付款主体都不一致,就会进一步增加风险。

  1. 涉及需要资质的行业

有些行业不是随便一个开发者账号就能提交。

比如:

  1. 金融借贷类;
  2. 证券基金类;
  3. 医疗健康类;
  4. 保险类;
  5. 教育培训类;
  6. 彩票博彩类;
  7. 虚拟币、虚拟资产类;
  8. 电商交易类;
  9. 支付类;
  10. 政务、公共服务类。

如果 App 涉及这些方向,但没有提供对应资质,或者资质主体和开发者主体不一致,就容易触发 3.2。

  1. 代上架痕迹明显

苹果比较关注开发者账号是否被用于给第三方代上架。

比如:

  1. 一个账号下提交多个不同客户的 App;
  2. App 内品牌和开发者名称完全不一致;
  3. 客服电话、网站、公司名称、隐私政策主体不一致;
  4. 账号主体和 App 实际运营主体不一致;
  5. 不同 App 业务跨度很大;
  6. 同账号频繁提交各种不相关类型的 App;
  7. 审核备注无法说明开发者和 App 的关系。

如果苹果认为账号不是实际运营方,而是在代替别人上架,就可能触发更严重的账号风险。

  1. App 存在误导用户或商业模式不清晰

有些 App 在标题、截图、描述里宣传得很夸张,但实际功能很简单,甚至和描述不一致。还有一些 App 通过诱导订阅、隐藏收费、模糊价格、夸大效果等方式吸引用户,也容易触发 3.2。

比如:

  1. 截图展示的功能 App 内没有;
  2. 描述夸大服务效果;
  3. 订阅价格不清楚;
  4. 试用规则不透明;
  5. 用户无法取消或管理服务;
  6. App 内服务承诺无法兑现;
  7. 用擦边文案吸引用户下载;
  8. 功能包装和实际内容不一致。

这种情况即使不封号,也很容易被拒。

  1. 反复提交高风险 App

如果一个账号多次提交被拒的 App,尤其是涉及 3.2、4.3、5.2.3、1.2、3.1.2 等问题,账号历史会越来越敏感。

比如:

  1. 被拒后没有解决根本问题,直接重提;
  2. 多次修改一点点继续碰运气;
  3. 频繁撤回、频繁提交;
  4. 多次尝试不同包名、不同名称;
  5. 同类型 App 在账号下反复出现;
  6. 明显有规避审核的痕迹。

这类行为可能让苹果认为开发者没有认真遵守审核规则,从而进一步处理账号。

  1. 资料不真实或前后不一致

苹果非常看重开发者资料的真实性。

如果 App Store Connect 信息、开发者账号信息、公司资料、网站信息、隐私政策、用户协议、App 内展示信息不一致,就容易被认为存在风险。

常见问题包括:

  1. 隐私政策里的公司名和开发者账号主体不同;
  2. App 内客服主体和开发者主体不同;
  3. 网站备案主体和 App 主体不同;
  4. 营业执照和实际业务不匹配;
  5. 审核备注里解释不清楚;
  6. 使用了不属于自己的品牌或资质;
  7. 提供的材料模糊、不完整、不可信。

这些问题都会影响账号可信度。

四、遇到 3.2 后不要做什么?

遇到 3.2 后,最忌讳乱操作。

不建议做以下事情:

  1. 不看原因,直接重新提交;
  2. 只改名字、截图、图标;
  3. 换一个包继续提交;
  4. 频繁催审核或加急;
  5. 申诉时情绪化表达;
  6. 提供无法证明的解释;
  7. 使用虚假资料补充审核;
  8. 继续用同账号提交类似 App;
  9. 把责任推给审核员;
  10. 复制模板申诉信直接发送。

3.2 问题更像是信任问题。你的申诉重点不是“求苹果放过”,而是证明:账号主体真实、业务真实、资质真实、App 归属清晰、没有误导用户、没有代上架、没有规避审核。

五、3.2 封号后应该先做什么?

  1. 先看苹果邮件原文

不要只看“3.2”这个编号,要看苹果具体写了什么。不同邮件的严重程度不一样。

你要重点看:

  1. 是 App 被拒,还是账号被终止;
  2. 是否要求提供材料;
  3. 是否提到欺诈、误导、规避审核;
  4. 是否提到开发者计划协议;
  5. 是否给了申诉入口;
  6. 是否允许继续解释;
  7. 是否要求证明 App 所属关系。

如果邮件里已经涉及账号终止,就不能再当普通拒审处理。

  1. 梳理 App 和主体关系

你要先把关系说清楚:

  1. 这个 App 是谁运营的;
  2. 开发者账号主体是谁;
  3. App 内品牌属于谁;
  4. 隐私政策主体是谁;
  5. 用户协议主体是谁;
  6. 客服和网站主体是谁;
  7. 是否有授权关系;
  8. 是否有相关资质。

如果 App 是公司自己的产品,要证明开发者主体和产品主体一致。

如果 App 是客户产品,最好有清晰授权材料,但代上架本身就容易带来风险。

  1. 准备资质和证明材料

根据业务类型准备材料。

可能需要的材料包括:

  1. 营业执照;
  2. 品牌授权书;
  3. 软件著作权;
  4. 网站备案信息;
  5. 行业许可证;
  6. 业务资质;
  7. App 运营说明;
  8. 隐私政策和用户协议;
  9. 公司官网;
  10. 客服联系方式;
  11. App 功能说明文档;
  12. 与 App 品牌相关的证明材料。

材料一定要真实、清晰、对应得上,不要临时拼凑。

  1. 检查 App 内外一致性

申诉前建议统一以下信息:

  1. App 名称;
  2. 开发者名称;
  3. 公司名称;
  4. 隐私政策主体;
  5. 用户协议主体;
  6. 官网备案主体;
  7. 客服邮箱;
  8. App 内关于我们页面;
  9. 审核备注;
  10. App Store 描述。

信息越统一,可信度越高。

六、3.2 怎么申诉?

申诉时要注意四个原则:

  1. 态度要客观

不要质问审核员,也不要说“为什么别人可以我不可以”。苹果更看重事实和证明材料。

  1. 解释要具体

不要只写“我们没有违规”。要说明 App 是什么、谁运营、服务对象是谁、是否有资质、如何保障用户权益。

  1. 材料要完整

如果涉及资质,尽量一次性提供清楚。不要一句话解释半天,但没有任何证明。

  1. 承诺要真实

可以说明已经整改了哪些内容,但不要承诺无法执行的东西。

七、3.2 申诉信模板

下面是一份比较稳的申诉模板,可以根据实际情况修改。

Hello App Review Team,
Thank you for reviewing our app and providing feedback.
We understand that the issue is related to Guideline 3.2 and the business compliance of our app. We take this matter seriously and have carefully reviewed our app, account information, business model, metadata, privacy policy, and user-facing content.
Our app is operated by [公司名称], and the Apple Developer account is also registered under [开发者主体名称]. The app is designed to provide [简要说明 App 的核心功能和服务对象]. We confirm that the app is not submitted on behalf of an unrelated third party, and it is not intended to mislead users or bypass the App Review process.
To address the concern, we have completed the following updates:

  1. Updated the app description to clearly explain the app’s core features and target users.
  2. Updated the review notes to help the review team understand the app’s usage flow.
  3. Verified that the privacy policy and terms of service are accessible and consistent with the app.
  4. Ensured that the company name, app branding, support contact, and website information are consistent.
  5. Reviewed the app content to make sure there is no misleading business information.
  6. Prepared supporting documents to verify our business ownership and qualification.
    If needed, we can provide the following supporting documents:
  7. Business license.
  8. App ownership or authorization documents.
  9. Website and company information.
  10. Relevant industry qualification documents.
  11. Additional explanation of the app’s business model and user flow.
    We respectfully request the App Review Team to reconsider our case. If there is any specific information or document required, we are willing to provide it promptly.
    Thank you for your time and support.
    Best regards,
    [姓名 / 公司名称]

八、中文申诉思路参考

如果你要先整理中文版本,可以这样写:

您好,App Review 团队:
感谢您对我们 App 的审核反馈。
我们已经认真阅读了关于 Guideline 3.2 的审核意见,并对 App 的业务模式、开发者主体、资质材料、隐私政策、用户协议、App Store 元数据以及 App 内展示内容进行了全面检查。
当前 App 由【公司名称】运营,开发者账号主体为【开发者主体名称】。该 App 主要用于【说明 App 核心功能】,服务对象为【说明用户群体】。我们确认该 App 并非代表无关第三方提交,也不存在误导用户或规避 App Review 的情况。
针对本次反馈,我们已经完成以下调整:

  1. 重新整理了 App Store 描述,明确 App 的核心功能和使用场景;
  2. 完善了审核备注,方便审核团队理解 App 的主要流程;
  3. 检查并统一了隐私政策、用户协议、公司名称、客服信息和官网信息;
  4. 核查了 App 内的功能展示,避免出现误导性描述;
  5. 准备了营业执照、授权证明、业务说明等相关材料;
  6. 对 App 内涉及商业服务的内容进行了合规检查。
    如果审核团队需要进一步确认,我们可以继续提供营业执照、品牌授权、业务资质、官网信息、App 功能说明等证明材料。
    我们尊重 App Review 的审核规则,也希望能够进一步说明我们的业务真实性和 App 合规性。恳请审核团队重新评估我们的提交。如仍有需要补充的材料,我们会第一时间配合提供。
    感谢您的时间和支持。

九、申诉材料怎么组织?

建议材料不要乱发,最好整理成清晰的说明。

可以按这个顺序组织:

  1. 公司主体说明;
  2. App 业务说明;
  3. App 和公司之间的关系;
  4. 用户使用流程;
  5. 是否涉及资质;
  6. 已经完成的整改内容;
  7. 可提供的证明材料;
  8. 联系方式和官网地址。

如果是截图材料,可以命名清楚:

  1. business_license.pdf
  2. app_ownership_statement.pdf
  3. privacy_policy_screenshot.png
  4. terms_of_service_screenshot.png
  5. app_user_flow.pdf
  6. qualification_documents.pdf

材料越清晰,审核团队越容易判断。

十、申诉成功的关键是什么?

3.2 申诉成功的关键不是写得多,而是能不能证明三个点:

第一,主体真实。

开发者账号、公司主体、App 品牌、官网、隐私政策、客服信息要能对应起来。

第二,业务合规。

App 的业务不能是平台明确不允许或高风险但无资质的方向。如果涉及特殊行业,要有对应证明。

第三,解释清楚。

审核员要能快速理解这个 App 是做什么的、谁运营、给谁用、为什么合规。

如果这三个点说不清楚,申诉信写得再长也很难解决问题。

十一、总结

苹果 3.2 问题比普通拒审更严重,因为它往往涉及商业模式、账号主体、资质证明、业务真实性和开发者可信度。轻微情况可能只是 App 被拒,严重情况可能导致账号被调查甚至封号。

遇到 3.2 不要急着重新提交,也不要只做表面修改。正确做法是先分析苹果邮件内容,再梳理账号主体、App 归属、业务资质、隐私政策、用户协议、官网信息和审核备注。

申诉时不要情绪化,不要套模板硬发,而是要围绕“主体真实、业务真实、资质真实、信息一致、用户不被误导”这几个核心点来说明。

如果账号已经被封,更要谨慎处理。这个时候重点不是继续提交新包,而是通过申诉材料证明账号和 App 的合规性。只有把信任问题解释清楚,才有机会让苹果重新评估。

继续阅读 »

苹果上架遇到 3.2 封号怎么办?原因是什么?应该怎么申诉?

在 App Store 上架过程中,很多开发者最怕遇到两类问题:一种是 App 被拒,另一种就是开发者账号被调查甚至被封。相比普通拒审,3.2 相关问题往往更麻烦,因为它不只是某个版本的问题,还可能涉及账号主体、业务模式、资质材料、开发者身份、商业合规等多个方面。

很多人看到 3.2 后第一反应是:“是不是 App 有问题?”其实不一定。3.2 更偏向商业模式、开发者身份、资质真实性、业务合规性、是否存在误导用户、是否存在代上架或批量上架等问题。如果处理不当,轻则 App 被拒,重则账号被限制、调查,甚至终止开发者计划。

一、苹果 3.2 主要看什么?

苹果审核指南 3.2 属于“Business”商业相关规则,重点关注 App 的商业模式是否合理、开发者身份是否真实、服务是否合规、是否存在误导用户或不符合平台规则的行为。

简单理解,苹果会关注以下几个问题:

  1. 这个 App 的业务是否真实存在;
  2. 开发者是否有资格提供这个服务;
  3. App 是否涉及需要资质的行业;
  4. App 是否存在误导用户的商业行为;
  5. App 是否是给别人代上架;
  6. 账号主体和 App 业务是否匹配;
  7. 是否存在批量提交、重复提交、规避审核的行为;
  8. 是否存在虚假资料、虚假功能、虚假宣传;
  9. 是否存在高风险业务,比如金融、医疗、借贷、博彩、虚拟资产等;
  10. 是否违反了 Apple Developer Program License Agreement。

所以,3.2 不是简单改几句文案就一定能解决的问题。它通常需要从账号、资质、业务、App 内容、审核说明多个方面一起处理。

二、为什么 3.2 会导致封号?

普通拒审一般只影响当前版本,但 3.2 如果严重,就可能影响整个开发者账号。

原因很简单:苹果可能认为问题不是 App 的某个页面,而是账号本身存在风险。比如开发者账号和实际业务不匹配、提交的 App 不属于账号主体经营范围、存在代上架嫌疑、重复提交高风险应用、使用虚假资料、绕过审核规则等。

一旦苹果认为账号存在信任问题,就可能不只是拒绝 App,而是对账号进行进一步审核。这个时候开发者可能会收到类似账号调查、账号终止、开发者计划被移除等邮件。

常见表现包括:

  1. App 审核中突然被拒;
  2. App Store Connect 功能受限;
  3. 新版本无法继续提交;
  4. 账号收到调查邮件;
  5. 账号被要求提供业务资质;
  6. 账号被要求解释 App 归属;
  7. 账号被终止开发者计划;
  8. 同主体或相关账号后续提交变得更难。

所以,遇到 3.2 不要简单当作普通拒审处理,更不要频繁重复提交。

三、3.2 封号常见原因

  1. 账号主体和 App 业务不匹配

这是非常常见的原因。

比如账号主体是一家普通科技公司,但提交的 App 是金融、借贷、医疗、保险、证券、心理咨询、算命、支付、数字藏品、虚拟资产等业务。苹果可能会要求证明你有资格提供这些服务。

如果主体资料、营业执照经营范围、网站备案、隐私政策、App 内品牌、客服信息、付款主体都不一致,就会进一步增加风险。

  1. 涉及需要资质的行业

有些行业不是随便一个开发者账号就能提交。

比如:

  1. 金融借贷类;
  2. 证券基金类;
  3. 医疗健康类;
  4. 保险类;
  5. 教育培训类;
  6. 彩票博彩类;
  7. 虚拟币、虚拟资产类;
  8. 电商交易类;
  9. 支付类;
  10. 政务、公共服务类。

如果 App 涉及这些方向,但没有提供对应资质,或者资质主体和开发者主体不一致,就容易触发 3.2。

  1. 代上架痕迹明显

苹果比较关注开发者账号是否被用于给第三方代上架。

比如:

  1. 一个账号下提交多个不同客户的 App;
  2. App 内品牌和开发者名称完全不一致;
  3. 客服电话、网站、公司名称、隐私政策主体不一致;
  4. 账号主体和 App 实际运营主体不一致;
  5. 不同 App 业务跨度很大;
  6. 同账号频繁提交各种不相关类型的 App;
  7. 审核备注无法说明开发者和 App 的关系。

如果苹果认为账号不是实际运营方,而是在代替别人上架,就可能触发更严重的账号风险。

  1. App 存在误导用户或商业模式不清晰

有些 App 在标题、截图、描述里宣传得很夸张,但实际功能很简单,甚至和描述不一致。还有一些 App 通过诱导订阅、隐藏收费、模糊价格、夸大效果等方式吸引用户,也容易触发 3.2。

比如:

  1. 截图展示的功能 App 内没有;
  2. 描述夸大服务效果;
  3. 订阅价格不清楚;
  4. 试用规则不透明;
  5. 用户无法取消或管理服务;
  6. App 内服务承诺无法兑现;
  7. 用擦边文案吸引用户下载;
  8. 功能包装和实际内容不一致。

这种情况即使不封号,也很容易被拒。

  1. 反复提交高风险 App

如果一个账号多次提交被拒的 App,尤其是涉及 3.2、4.3、5.2.3、1.2、3.1.2 等问题,账号历史会越来越敏感。

比如:

  1. 被拒后没有解决根本问题,直接重提;
  2. 多次修改一点点继续碰运气;
  3. 频繁撤回、频繁提交;
  4. 多次尝试不同包名、不同名称;
  5. 同类型 App 在账号下反复出现;
  6. 明显有规避审核的痕迹。

这类行为可能让苹果认为开发者没有认真遵守审核规则,从而进一步处理账号。

  1. 资料不真实或前后不一致

苹果非常看重开发者资料的真实性。

如果 App Store Connect 信息、开发者账号信息、公司资料、网站信息、隐私政策、用户协议、App 内展示信息不一致,就容易被认为存在风险。

常见问题包括:

  1. 隐私政策里的公司名和开发者账号主体不同;
  2. App 内客服主体和开发者主体不同;
  3. 网站备案主体和 App 主体不同;
  4. 营业执照和实际业务不匹配;
  5. 审核备注里解释不清楚;
  6. 使用了不属于自己的品牌或资质;
  7. 提供的材料模糊、不完整、不可信。

这些问题都会影响账号可信度。

四、遇到 3.2 后不要做什么?

遇到 3.2 后,最忌讳乱操作。

不建议做以下事情:

  1. 不看原因,直接重新提交;
  2. 只改名字、截图、图标;
  3. 换一个包继续提交;
  4. 频繁催审核或加急;
  5. 申诉时情绪化表达;
  6. 提供无法证明的解释;
  7. 使用虚假资料补充审核;
  8. 继续用同账号提交类似 App;
  9. 把责任推给审核员;
  10. 复制模板申诉信直接发送。

3.2 问题更像是信任问题。你的申诉重点不是“求苹果放过”,而是证明:账号主体真实、业务真实、资质真实、App 归属清晰、没有误导用户、没有代上架、没有规避审核。

五、3.2 封号后应该先做什么?

  1. 先看苹果邮件原文

不要只看“3.2”这个编号,要看苹果具体写了什么。不同邮件的严重程度不一样。

你要重点看:

  1. 是 App 被拒,还是账号被终止;
  2. 是否要求提供材料;
  3. 是否提到欺诈、误导、规避审核;
  4. 是否提到开发者计划协议;
  5. 是否给了申诉入口;
  6. 是否允许继续解释;
  7. 是否要求证明 App 所属关系。

如果邮件里已经涉及账号终止,就不能再当普通拒审处理。

  1. 梳理 App 和主体关系

你要先把关系说清楚:

  1. 这个 App 是谁运营的;
  2. 开发者账号主体是谁;
  3. App 内品牌属于谁;
  4. 隐私政策主体是谁;
  5. 用户协议主体是谁;
  6. 客服和网站主体是谁;
  7. 是否有授权关系;
  8. 是否有相关资质。

如果 App 是公司自己的产品,要证明开发者主体和产品主体一致。

如果 App 是客户产品,最好有清晰授权材料,但代上架本身就容易带来风险。

  1. 准备资质和证明材料

根据业务类型准备材料。

可能需要的材料包括:

  1. 营业执照;
  2. 品牌授权书;
  3. 软件著作权;
  4. 网站备案信息;
  5. 行业许可证;
  6. 业务资质;
  7. App 运营说明;
  8. 隐私政策和用户协议;
  9. 公司官网;
  10. 客服联系方式;
  11. App 功能说明文档;
  12. 与 App 品牌相关的证明材料。

材料一定要真实、清晰、对应得上,不要临时拼凑。

  1. 检查 App 内外一致性

申诉前建议统一以下信息:

  1. App 名称;
  2. 开发者名称;
  3. 公司名称;
  4. 隐私政策主体;
  5. 用户协议主体;
  6. 官网备案主体;
  7. 客服邮箱;
  8. App 内关于我们页面;
  9. 审核备注;
  10. App Store 描述。

信息越统一,可信度越高。

六、3.2 怎么申诉?

申诉时要注意四个原则:

  1. 态度要客观

不要质问审核员,也不要说“为什么别人可以我不可以”。苹果更看重事实和证明材料。

  1. 解释要具体

不要只写“我们没有违规”。要说明 App 是什么、谁运营、服务对象是谁、是否有资质、如何保障用户权益。

  1. 材料要完整

如果涉及资质,尽量一次性提供清楚。不要一句话解释半天,但没有任何证明。

  1. 承诺要真实

可以说明已经整改了哪些内容,但不要承诺无法执行的东西。

七、3.2 申诉信模板

下面是一份比较稳的申诉模板,可以根据实际情况修改。

Hello App Review Team,
Thank you for reviewing our app and providing feedback.
We understand that the issue is related to Guideline 3.2 and the business compliance of our app. We take this matter seriously and have carefully reviewed our app, account information, business model, metadata, privacy policy, and user-facing content.
Our app is operated by [公司名称], and the Apple Developer account is also registered under [开发者主体名称]. The app is designed to provide [简要说明 App 的核心功能和服务对象]. We confirm that the app is not submitted on behalf of an unrelated third party, and it is not intended to mislead users or bypass the App Review process.
To address the concern, we have completed the following updates:

  1. Updated the app description to clearly explain the app’s core features and target users.
  2. Updated the review notes to help the review team understand the app’s usage flow.
  3. Verified that the privacy policy and terms of service are accessible and consistent with the app.
  4. Ensured that the company name, app branding, support contact, and website information are consistent.
  5. Reviewed the app content to make sure there is no misleading business information.
  6. Prepared supporting documents to verify our business ownership and qualification.
    If needed, we can provide the following supporting documents:
  7. Business license.
  8. App ownership or authorization documents.
  9. Website and company information.
  10. Relevant industry qualification documents.
  11. Additional explanation of the app’s business model and user flow.
    We respectfully request the App Review Team to reconsider our case. If there is any specific information or document required, we are willing to provide it promptly.
    Thank you for your time and support.
    Best regards,
    [姓名 / 公司名称]

八、中文申诉思路参考

如果你要先整理中文版本,可以这样写:

您好,App Review 团队:
感谢您对我们 App 的审核反馈。
我们已经认真阅读了关于 Guideline 3.2 的审核意见,并对 App 的业务模式、开发者主体、资质材料、隐私政策、用户协议、App Store 元数据以及 App 内展示内容进行了全面检查。
当前 App 由【公司名称】运营,开发者账号主体为【开发者主体名称】。该 App 主要用于【说明 App 核心功能】,服务对象为【说明用户群体】。我们确认该 App 并非代表无关第三方提交,也不存在误导用户或规避 App Review 的情况。
针对本次反馈,我们已经完成以下调整:

  1. 重新整理了 App Store 描述,明确 App 的核心功能和使用场景;
  2. 完善了审核备注,方便审核团队理解 App 的主要流程;
  3. 检查并统一了隐私政策、用户协议、公司名称、客服信息和官网信息;
  4. 核查了 App 内的功能展示,避免出现误导性描述;
  5. 准备了营业执照、授权证明、业务说明等相关材料;
  6. 对 App 内涉及商业服务的内容进行了合规检查。
    如果审核团队需要进一步确认,我们可以继续提供营业执照、品牌授权、业务资质、官网信息、App 功能说明等证明材料。
    我们尊重 App Review 的审核规则,也希望能够进一步说明我们的业务真实性和 App 合规性。恳请审核团队重新评估我们的提交。如仍有需要补充的材料,我们会第一时间配合提供。
    感谢您的时间和支持。

九、申诉材料怎么组织?

建议材料不要乱发,最好整理成清晰的说明。

可以按这个顺序组织:

  1. 公司主体说明;
  2. App 业务说明;
  3. App 和公司之间的关系;
  4. 用户使用流程;
  5. 是否涉及资质;
  6. 已经完成的整改内容;
  7. 可提供的证明材料;
  8. 联系方式和官网地址。

如果是截图材料,可以命名清楚:

  1. business_license.pdf
  2. app_ownership_statement.pdf
  3. privacy_policy_screenshot.png
  4. terms_of_service_screenshot.png
  5. app_user_flow.pdf
  6. qualification_documents.pdf

材料越清晰,审核团队越容易判断。

十、申诉成功的关键是什么?

3.2 申诉成功的关键不是写得多,而是能不能证明三个点:

第一,主体真实。

开发者账号、公司主体、App 品牌、官网、隐私政策、客服信息要能对应起来。

第二,业务合规。

App 的业务不能是平台明确不允许或高风险但无资质的方向。如果涉及特殊行业,要有对应证明。

第三,解释清楚。

审核员要能快速理解这个 App 是做什么的、谁运营、给谁用、为什么合规。

如果这三个点说不清楚,申诉信写得再长也很难解决问题。

十一、总结

苹果 3.2 问题比普通拒审更严重,因为它往往涉及商业模式、账号主体、资质证明、业务真实性和开发者可信度。轻微情况可能只是 App 被拒,严重情况可能导致账号被调查甚至封号。

遇到 3.2 不要急着重新提交,也不要只做表面修改。正确做法是先分析苹果邮件内容,再梳理账号主体、App 归属、业务资质、隐私政策、用户协议、官网信息和审核备注。

申诉时不要情绪化,不要套模板硬发,而是要围绕“主体真实、业务真实、资质真实、信息一致、用户不被误导”这几个核心点来说明。

如果账号已经被封,更要谨慎处理。这个时候重点不是继续提交新包,而是通过申诉材料证明账号和 App 的合规性。只有把信任问题解释清楚,才有机会让苹果重新评估。

收起阅读 »

苹果审核上架审核太慢了,怎么办?不要一上来就加急,尤其是多次 4.3 的账号

苹果审核上架审核太慢了,怎么办?

很多开发者在提交 App Store 审核后,最怕遇到的情况就是审核一直没有动静。后台状态可能一直停留在“等待审核”,也可能已经进入“正在审核”,但是一天、两天甚至更久都没有结果。这个时候很多人会开始着急:是不是包有问题?是不是账号有问题?要不要取消重新提交?要不要申请加急审核?

其实,苹果审核慢不一定代表异常。不同类型的 App、不同账号历史、不同功能复杂度,审核时间都会不一样。尤其是涉及登录、订阅、UGC、金融、工具、AI、资质、隐私权限、马甲包相似度等内容的 App,审核时间变长是比较常见的情况。

一、审核慢,先不要马上取消审核

很多人看到审核慢,第一反应就是取消审核,然后重新打包提交。这个操作不一定正确。

如果 App 只是刚提交没多久,比如 24 小时左右还在等待审核,一般不建议马上取消。因为取消后重新提交,等于重新进入审核队列,不一定会更快,反而可能浪费时间。

如果已经进入“正在审核”,也不要频繁撤回。这个阶段说明审核员可能已经开始查看你的 App。频繁撤回、频繁改包、频繁提交,有时反而会让审核记录变得更复杂。

正确做法是先检查以下几个地方:

  1. 测试账号是否能正常登录。
  2. App 是否需要验证码,审核员是否能顺利进入。
  3. 后台接口是否稳定。
  4. App 内核心功能是否能正常体验。
  5. 隐私政策、用户协议是否能打开。
  6. 订阅信息是否完整。
  7. 权限弹窗是否说明用途。
  8. 审核备注是否写清楚。
  9. 截图、标题、描述是否和实际功能一致。

如果这些基础信息没有问题,可以先观察,不要急着重新提交。

二、苹果审核可以加急,但不能乱用

苹果确实有加急审核机制。如果你的 App 有真实紧急情况,比如线上版本出现严重 bug、影响大量用户使用、重大活动即将开始、安全修复必须尽快上线,这种情况可以尝试申请加急审核。

但是,加急审核不是万能的。

加急的作用只是让苹果更快处理你的审核请求,并不代表会降低审核标准。如果你的 App 本身存在问题,比如 4.3 相似应用、功能不完整、资质不足、隐私合规没做好、订阅信息缺失、截图和功能不匹配,那么加急只会让问题更快暴露。

很多人误以为审核慢了就申请加急,结果反而很快收到拒绝。原因很简单:苹果不是因为你加急就放宽审核,而是更快进入审核流程。

所以,加急只能用在真正紧急的场景,不适合用来解决包本身的问题。

三、多次 4.3 的账号,更不建议随便加急

如果你的 App 之前已经多次收到 4.3,或者账号下提交过多个相似 App,那么审核慢的时候更要谨慎。

4.3 通常和重复 App、相似功能、低差异化、马甲包痕迹有关。这个问题不是靠加急能解决的,而是要从产品、代码、UI、素材、功能、账号环境等多个方面重新处理。

特别是多次 4.3 之后,如果你没有做明显修改,只是换个包、换个图标、换个名字继续提交,再去申请加急,风险会更高。因为审核员可能会更快关注到你的历史记录和当前版本之间的相似性。

严格来说,真正导致账号风险升高的不是“申请一次加急”本身,而是长期反复提交高风险包、重复违规、问题没有解决还一直提交。加急只是让审核更快发生,如果包本身风险没处理干净,结果往往不会更好。

所以,多次 4.3 的账号,建议先处理以下问题:

  1. App 定位是否和之前的包明显不同。
  2. 核心功能是否有真实差异。
  3. UI 页面是否还是同一套模板。
  4. 代码结构是否高度相似。
  5. 接口、资源、素材是否重复。
  6. 隐私政策和协议是否独立。
  7. App Store 截图和描述是否像批量生成。
  8. 审核备注是否能说明 App 的真实价值。

这些没有处理好之前,不建议直接加急。

四、审核太慢时,正确处理顺序

第一步,先看审核状态。

如果只是“等待审核”,可以先观察。如果已经“正在审核”,不要频繁撤回。

第二步,检查基础资料。

重点检查测试账号、审核备注、隐私政策、用户协议、订阅信息、权限说明、App 内功能入口。很多 App 审核慢,不是苹果故意卡,而是审核员无法快速判断 App 的完整性。

第三步,判断是否存在高风险。

如果你的 App 属于工具类、AI 类、教育类、算命类、金融类、UGC 类、订阅类,或者之前有过 4.3、2.1、3.2、5.2.3 等拒绝记录,就要更加谨慎。不要把审核慢简单理解成“苹果没看到”,它也可能是在更细地看。

第四步,必要时联系苹果。

可以通过 App Store Connect 联系审核团队,询问当前审核状态,或者补充说明信息。语气要客观,不要催促、抱怨,也不要写得太情绪化。

第五步,确实紧急时,再申请加急。

如果没有真实紧急原因,不建议随便申请加急。尤其是多次 4.3 的账号,更建议先排查包体和资料问题。

五、什么情况适合申请加急?

以下情况可以考虑申请加急:

  1. 线上版本存在严重 bug。
  2. App 无法正常使用,影响大量用户。
  3. 版本涉及安全修复。
  4. 有明确时间节点的活动。
  5. App 是活动、课程、服务上线的必要工具。
  6. 当前版本必须尽快替换旧版本。

加急理由一定要真实、具体、可验证。比如:

当前版本用于修复线上严重崩溃问题,该问题会影响用户正常使用核心功能,希望申请加急审核。

这种理由相对合理。

不建议写下面这些理由:

客户很着急。
老板催上线。
已经等了一天。
我们想尽快发布。
别人都审核通过了。

这些理由通常不够充分,也容易显得不专业。

六、什么情况不建议加急?

以下情况不建议加急:

  1. 刚提交一天左右。
  2. 没有真实紧急原因。
  3. 之前刚被 4.3 拒绝。
  4. 包体没有做明显修改。
  5. 账号近期频繁提交类似 App。
  6. 测试账号不稳定。
  7. 审核备注没写清楚。
  8. 隐私政策、订阅、权限说明还没整理好。
  9. App 功能本身还不完整。
  10. 只是单纯想快点上线。

审核慢的时候,最怕的不是等待,而是乱操作。频繁撤回、频繁提交、频繁加急,有时会让账号和 App 的审核记录越来越敏感。

七、可以这样联系苹果

如果只是想询问审核状态,可以这样写:

您好,我们的 App 当前已提交审核,目前仍处于等待审核或正在审核状态。我们已经确认测试账号、核心功能、隐私政策、权限说明和审核备注均可正常使用。如果审核过程中需要更多信息,我们可以随时配合补充。感谢审核团队的处理。

如果确实需要申请加急,可以这样写:

您好,当前版本主要用于修复线上严重问题,该问题会影响用户正常使用核心功能。我们希望申请加急审核,以便尽快为用户提供稳定版本。我们理解加急审核仅适用于紧急情况,也会尊重 App Review 的审核流程。感谢审核团队的支持。

注意,语气一定要稳,不要写成催促,不要质问审核员,也不要把加急当成投诉。

八、总结

苹果审核太慢,不一定代表 App 有问题,但也不能完全忽视。正确做法是先判断状态,再检查资料,最后再考虑是否联系苹果或申请加急。

加急审核确实可以申请,但不要乱用。它适合真实紧急场景,不适合用来解决 4.3、相似度、资质、功能包装、隐私合规等根本问题。

尤其是多次 4.3 的账号,更要谨慎。这个时候重点不是催审核,而是先把 App 本身处理干净,包括功能差异、UI 差异、代码差异、素材差异、审核备注、隐私合规、账号环境等。

审核慢可以等,可以沟通,也可以在必要时加急。但真正影响过审结果的,还是 App 是否独立、完整、合规、有真实价值。不要把加急当成捷径,尤其不要在包本身风险很高的时候频繁加急,否则很容易让问题更快暴露,甚至影响后续审核节奏。

更多资料查看我主页信息

继续阅读 »

苹果审核上架审核太慢了,怎么办?

很多开发者在提交 App Store 审核后,最怕遇到的情况就是审核一直没有动静。后台状态可能一直停留在“等待审核”,也可能已经进入“正在审核”,但是一天、两天甚至更久都没有结果。这个时候很多人会开始着急:是不是包有问题?是不是账号有问题?要不要取消重新提交?要不要申请加急审核?

其实,苹果审核慢不一定代表异常。不同类型的 App、不同账号历史、不同功能复杂度,审核时间都会不一样。尤其是涉及登录、订阅、UGC、金融、工具、AI、资质、隐私权限、马甲包相似度等内容的 App,审核时间变长是比较常见的情况。

一、审核慢,先不要马上取消审核

很多人看到审核慢,第一反应就是取消审核,然后重新打包提交。这个操作不一定正确。

如果 App 只是刚提交没多久,比如 24 小时左右还在等待审核,一般不建议马上取消。因为取消后重新提交,等于重新进入审核队列,不一定会更快,反而可能浪费时间。

如果已经进入“正在审核”,也不要频繁撤回。这个阶段说明审核员可能已经开始查看你的 App。频繁撤回、频繁改包、频繁提交,有时反而会让审核记录变得更复杂。

正确做法是先检查以下几个地方:

  1. 测试账号是否能正常登录。
  2. App 是否需要验证码,审核员是否能顺利进入。
  3. 后台接口是否稳定。
  4. App 内核心功能是否能正常体验。
  5. 隐私政策、用户协议是否能打开。
  6. 订阅信息是否完整。
  7. 权限弹窗是否说明用途。
  8. 审核备注是否写清楚。
  9. 截图、标题、描述是否和实际功能一致。

如果这些基础信息没有问题,可以先观察,不要急着重新提交。

二、苹果审核可以加急,但不能乱用

苹果确实有加急审核机制。如果你的 App 有真实紧急情况,比如线上版本出现严重 bug、影响大量用户使用、重大活动即将开始、安全修复必须尽快上线,这种情况可以尝试申请加急审核。

但是,加急审核不是万能的。

加急的作用只是让苹果更快处理你的审核请求,并不代表会降低审核标准。如果你的 App 本身存在问题,比如 4.3 相似应用、功能不完整、资质不足、隐私合规没做好、订阅信息缺失、截图和功能不匹配,那么加急只会让问题更快暴露。

很多人误以为审核慢了就申请加急,结果反而很快收到拒绝。原因很简单:苹果不是因为你加急就放宽审核,而是更快进入审核流程。

所以,加急只能用在真正紧急的场景,不适合用来解决包本身的问题。

三、多次 4.3 的账号,更不建议随便加急

如果你的 App 之前已经多次收到 4.3,或者账号下提交过多个相似 App,那么审核慢的时候更要谨慎。

4.3 通常和重复 App、相似功能、低差异化、马甲包痕迹有关。这个问题不是靠加急能解决的,而是要从产品、代码、UI、素材、功能、账号环境等多个方面重新处理。

特别是多次 4.3 之后,如果你没有做明显修改,只是换个包、换个图标、换个名字继续提交,再去申请加急,风险会更高。因为审核员可能会更快关注到你的历史记录和当前版本之间的相似性。

严格来说,真正导致账号风险升高的不是“申请一次加急”本身,而是长期反复提交高风险包、重复违规、问题没有解决还一直提交。加急只是让审核更快发生,如果包本身风险没处理干净,结果往往不会更好。

所以,多次 4.3 的账号,建议先处理以下问题:

  1. App 定位是否和之前的包明显不同。
  2. 核心功能是否有真实差异。
  3. UI 页面是否还是同一套模板。
  4. 代码结构是否高度相似。
  5. 接口、资源、素材是否重复。
  6. 隐私政策和协议是否独立。
  7. App Store 截图和描述是否像批量生成。
  8. 审核备注是否能说明 App 的真实价值。

这些没有处理好之前,不建议直接加急。

四、审核太慢时,正确处理顺序

第一步,先看审核状态。

如果只是“等待审核”,可以先观察。如果已经“正在审核”,不要频繁撤回。

第二步,检查基础资料。

重点检查测试账号、审核备注、隐私政策、用户协议、订阅信息、权限说明、App 内功能入口。很多 App 审核慢,不是苹果故意卡,而是审核员无法快速判断 App 的完整性。

第三步,判断是否存在高风险。

如果你的 App 属于工具类、AI 类、教育类、算命类、金融类、UGC 类、订阅类,或者之前有过 4.3、2.1、3.2、5.2.3 等拒绝记录,就要更加谨慎。不要把审核慢简单理解成“苹果没看到”,它也可能是在更细地看。

第四步,必要时联系苹果。

可以通过 App Store Connect 联系审核团队,询问当前审核状态,或者补充说明信息。语气要客观,不要催促、抱怨,也不要写得太情绪化。

第五步,确实紧急时,再申请加急。

如果没有真实紧急原因,不建议随便申请加急。尤其是多次 4.3 的账号,更建议先排查包体和资料问题。

五、什么情况适合申请加急?

以下情况可以考虑申请加急:

  1. 线上版本存在严重 bug。
  2. App 无法正常使用,影响大量用户。
  3. 版本涉及安全修复。
  4. 有明确时间节点的活动。
  5. App 是活动、课程、服务上线的必要工具。
  6. 当前版本必须尽快替换旧版本。

加急理由一定要真实、具体、可验证。比如:

当前版本用于修复线上严重崩溃问题,该问题会影响用户正常使用核心功能,希望申请加急审核。

这种理由相对合理。

不建议写下面这些理由:

客户很着急。
老板催上线。
已经等了一天。
我们想尽快发布。
别人都审核通过了。

这些理由通常不够充分,也容易显得不专业。

六、什么情况不建议加急?

以下情况不建议加急:

  1. 刚提交一天左右。
  2. 没有真实紧急原因。
  3. 之前刚被 4.3 拒绝。
  4. 包体没有做明显修改。
  5. 账号近期频繁提交类似 App。
  6. 测试账号不稳定。
  7. 审核备注没写清楚。
  8. 隐私政策、订阅、权限说明还没整理好。
  9. App 功能本身还不完整。
  10. 只是单纯想快点上线。

审核慢的时候,最怕的不是等待,而是乱操作。频繁撤回、频繁提交、频繁加急,有时会让账号和 App 的审核记录越来越敏感。

七、可以这样联系苹果

如果只是想询问审核状态,可以这样写:

您好,我们的 App 当前已提交审核,目前仍处于等待审核或正在审核状态。我们已经确认测试账号、核心功能、隐私政策、权限说明和审核备注均可正常使用。如果审核过程中需要更多信息,我们可以随时配合补充。感谢审核团队的处理。

如果确实需要申请加急,可以这样写:

您好,当前版本主要用于修复线上严重问题,该问题会影响用户正常使用核心功能。我们希望申请加急审核,以便尽快为用户提供稳定版本。我们理解加急审核仅适用于紧急情况,也会尊重 App Review 的审核流程。感谢审核团队的支持。

注意,语气一定要稳,不要写成催促,不要质问审核员,也不要把加急当成投诉。

八、总结

苹果审核太慢,不一定代表 App 有问题,但也不能完全忽视。正确做法是先判断状态,再检查资料,最后再考虑是否联系苹果或申请加急。

加急审核确实可以申请,但不要乱用。它适合真实紧急场景,不适合用来解决 4.3、相似度、资质、功能包装、隐私合规等根本问题。

尤其是多次 4.3 的账号,更要谨慎。这个时候重点不是催审核,而是先把 App 本身处理干净,包括功能差异、UI 差异、代码差异、素材差异、审核备注、隐私合规、账号环境等。

审核慢可以等,可以沟通,也可以在必要时加急。但真正影响过审结果的,还是 App 是否独立、完整、合规、有真实价值。不要把加急当成捷径,尤其不要在包本身风险很高的时候频繁加急,否则很容易让问题更快暴露,甚至影响后续审核节奏。

更多资料查看我主页信息

收起阅读 »