HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

1

1

1

1

1

1

2

2

2

1

1

1

uniCloud

uniCloud

背景和优势
20年前,restful接口开发开始流行,服务器编写接口,客户端调用接口,传输json。

现在,替代restful的新模式来了。

云对象,服务器编写API,客户端调用API,不再开发传输json的接口。思路更清晰、代码更精简。

比如服务端编写一个云对象todo,该对象有add、get、remove、update等方法。客户端的js则可以直接import这个todo云对象,直接调用add等方法。

服务器示例代码如下:

HBuilderX中在uniCloud/cloudfunctions目录新建云函数,选择类型为云对象,起名为todo。打开云对象入口index.obj.js,添加一个add方法。

// 云对象名:todo
module.exports = {
add(title, content) {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
然后在客户端的js中,import这个todo对象,调用它的add方法

const todo = uniCloud.importObject('todo') //第一步导入云对象
async function addTodo () {
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
uni.showToast({
title: '创建成功'
})
} catch (e) {
// 符合uniCloud响应体规范 https://doc.dcloud.net.cn/uniCloud/cf-functions?id=resformat,自动抛出此错误
uni.showModal({
title: '创建失败',
content: e.errMsg,
showCancel: false
})
}
}
复制代码
可以看到云对象的代码非常清晰,代码行数也只有33行。

而同样的逻辑,使用传统的接口方式则需要更多代码,见下:

// 传统方式调用云函数-云函数代码
// 云函数名:todo
// 云函数入口index.js内容如下
'use strict';
exports.main = async (event, context) => {
const {
method,
params
} = event
switch(method) {
case 'add': {
let {
title,
content
} = params
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...省略其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
return {
errCode: 'METHOD_NOT_FOUND',
errMsg: Method[${method}] not found
}
};

// 传统方式调用云函数-客户端代码
async function addToDo () {
try {
const res = await uniCloud.callFunction({
name: 'todo',
data: {
method: 'add',
params: {
title: 'title demo',
content: 'content demo'
}
}
})
const {
errCode,
errMsg
} = res.result
if(errCode) {
uni.showModal({
title: '创建失败',
content: errMsg,
showCancel: false
})
return
}
uni.showToast({
title: '创建成功'
})
} catch (e) {
uni.showModal({
title: '创建失败',
content: e.message,
showCancel: false
})
}
}
复制代码
以上传统开发需要68行代码,对比云对象的33行代码,不但工作量大,而且逻辑也不如云对象清晰。

_注:以上例子仅用于方便初学者理解。实际开发中对于简单的数据库操作,使用clientDB在前端直接操作数据库是更简单、代码更少的方案,都不需要写云端代码。

总结下云对象带来的好处:

更清晰的逻辑
更精简的代码
更少的协作成本(以及矛盾~)
客户端调用时在ide里有完善的代码提示,方法参数均可提示。(传输json可没法在ide里提示)
默认支持uniCloud响应体规范,方便错误拦截和统一处理
快速上手
创建云对象
云对象,其实是对云函数的封装。和创建云函数一样,在uniCloud/cloudfunctions目录右键新建云函数,选择云对象类型,输入云对象名称创建云对象,此处以云对象todo为例,创建的云对象包含一个index.obj.js。

创建云对象

一个空的云对象内容如下

// cloudfunctions/todo/index.obj.js
module.exports = {

}
复制代码
默认云对象模板是不包含任何方法的,我们为此对象添加一个add方法作为示例。

// cloudfunctions/todo/index.obj.js
module.exports = {
add: function(title = '', content = '') {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑,如操作todo数据表添加数据
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
至此云对象todo已经有了一个可以访问的方法了。接下来看如何使用客户端调用此云对象内的方法

客户端调用
客户端通过uniCloud.importObject方法获取云对象的实例,并可以通过此实例调用云对象内的方法。用法如下

const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
复制代码
通过代码块cco可以快捷的输入以下代码:

const todo = uniCloud.importObject('todo')
复制代码
实际业务中需要考虑错误捕获,调用方式有两种:

try catch
const todo = uniCloud.importObject('todo')
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
console.log(res)
} catch (e) {
console.log(e.errCode)
console.log(e.errMsg)
}
复制代码
then catch(promise写法)
const todo = uniCloud.importObject('todo')
todo.add('title demo', 'content demo').then(res => {
console.log(res)
}).catch(e => {
console.log(e.errCode)
console.log(e.errMsg)
})
复制代码
importObject参数说明

interface ImportObjectOptions {
/**

  • 是否移除自动展示的ui
    */
    customUI?: boolean;
    /**
  • loading界面配置
    */
    loadingOptions?: ImportObjectLoadingOptions;
    /**
  • 错误提示配置
    */
    errorOptions?: ImportObjectErrorOptions;
    /**
  • 使用安全网络的方法及安全网络类型
    */
    secretMethods?: Record<string, 'none' | 'request' | 'response' | 'both'>;
    /**
  • 转化云对象内未捕获的错误或客户端网络错误
    */
    parseSystemError?: (params: ParseSystemErrorParams) => Promise<ParsedSystemError> | ParsedSystemError;
    }
    复制代码
    云对象的API
    云对象作为云函数的一种,可以调用所有node的API和uniCloud的API。

uniCloud有众多API,另见:uniCloud的API清单

除上述API之外,云对象的this对象还有一批专用方法来获取当前请求的上下文信息。

与云函数入参时的context不同,云对象没有context。它通过this对象挂载的几个内置方法来获取上下文信息。请注意开发者避免在this上挂载同名方法。

获取客户端信息
HBuilderX 3.4.9起此接口可获取所有客户端getSystemInfo返回的客户端信息,完整字段列表参考:getSystemInfo

接口形式

this.getClientInfo()

示例:

module.exports = {
add: function() {
const clientInfo = this.getClientInfo()
// clientInfo = {
// clientIP,
// appId,
// deviceId,
// source,
// //... 其他getSystemInfoSync返回值
// }
}
}
复制代码
返回值

getClientInfo返回的信息,是在客户端的uni.getSystemInfo的基础之上,增加了一些额外的信息。

除了getSystemInfo返回字段外,还包含以下信息

属性名 类型 说明
clientIP string 客户端ip
userAgent string 客户端ua,注意非本地运行环境下客户端getSystemInfoSync也会获取ua参数并上传给云对象,但是云对象会从http请求头里面获取ua而不是clientInfo里面的ua
source string 调用来源,返回值见下。HBuilderX 3.5.1+
requestId string 请求id。HBuilderX 3.5.1+
scene string 场景值。客户端uni.getLaunchOptionsSync返回的scene参数,新增于HBuilderX 3.5.1
getClientInfo().source,返回云函数调用来源,它的值域为:

取值 说明
client uni-app客户端导入云对象调用
function 由其他云函数或云对象调用
http 云对象URL化后通过http访问调用 HBuilderX 3.5.2+
timing 定时任务调用云对象 HBuilderX 3.5.2+
server 云函数上传并运行
注意事项

客户端上报的信息在理论上存在被篡改可能,实际业务中应验证前端传来的数据的合法性
除了clientIP外,其他客户端信息只有使用uni-app客户端以云对象的方式调用才能获取
云对象与云函数内获取客户端platform稍有不同,云函数未拉齐vue2、vue3版本app平台的platform值,vue2为app-plus,vue3为app。云对象无论客户端是vue2还是vue3,在app平台获取的platform均为app。这一点在使用uni-id时需要特别注意,详情见:uni-id文档 preferedAppPlatform
获取云端信息
接口形式

this.getCloudInfo()

示例

继续阅读 »

背景和优势
20年前,restful接口开发开始流行,服务器编写接口,客户端调用接口,传输json。

现在,替代restful的新模式来了。

云对象,服务器编写API,客户端调用API,不再开发传输json的接口。思路更清晰、代码更精简。

比如服务端编写一个云对象todo,该对象有add、get、remove、update等方法。客户端的js则可以直接import这个todo云对象,直接调用add等方法。

服务器示例代码如下:

HBuilderX中在uniCloud/cloudfunctions目录新建云函数,选择类型为云对象,起名为todo。打开云对象入口index.obj.js,添加一个add方法。

// 云对象名:todo
module.exports = {
add(title, content) {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
然后在客户端的js中,import这个todo对象,调用它的add方法

const todo = uniCloud.importObject('todo') //第一步导入云对象
async function addTodo () {
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
uni.showToast({
title: '创建成功'
})
} catch (e) {
// 符合uniCloud响应体规范 https://doc.dcloud.net.cn/uniCloud/cf-functions?id=resformat,自动抛出此错误
uni.showModal({
title: '创建失败',
content: e.errMsg,
showCancel: false
})
}
}
复制代码
可以看到云对象的代码非常清晰,代码行数也只有33行。

而同样的逻辑,使用传统的接口方式则需要更多代码,见下:

// 传统方式调用云函数-云函数代码
// 云函数名:todo
// 云函数入口index.js内容如下
'use strict';
exports.main = async (event, context) => {
const {
method,
params
} = event
switch(method) {
case 'add': {
let {
title,
content
} = params
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...省略其他逻辑
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
return {
errCode: 'METHOD_NOT_FOUND',
errMsg: Method[${method}] not found
}
};

// 传统方式调用云函数-客户端代码
async function addToDo () {
try {
const res = await uniCloud.callFunction({
name: 'todo',
data: {
method: 'add',
params: {
title: 'title demo',
content: 'content demo'
}
}
})
const {
errCode,
errMsg
} = res.result
if(errCode) {
uni.showModal({
title: '创建失败',
content: errMsg,
showCancel: false
})
return
}
uni.showToast({
title: '创建成功'
})
} catch (e) {
uni.showModal({
title: '创建失败',
content: e.message,
showCancel: false
})
}
}
复制代码
以上传统开发需要68行代码,对比云对象的33行代码,不但工作量大,而且逻辑也不如云对象清晰。

_注:以上例子仅用于方便初学者理解。实际开发中对于简单的数据库操作,使用clientDB在前端直接操作数据库是更简单、代码更少的方案,都不需要写云端代码。

总结下云对象带来的好处:

更清晰的逻辑
更精简的代码
更少的协作成本(以及矛盾~)
客户端调用时在ide里有完善的代码提示,方法参数均可提示。(传输json可没法在ide里提示)
默认支持uniCloud响应体规范,方便错误拦截和统一处理
快速上手
创建云对象
云对象,其实是对云函数的封装。和创建云函数一样,在uniCloud/cloudfunctions目录右键新建云函数,选择云对象类型,输入云对象名称创建云对象,此处以云对象todo为例,创建的云对象包含一个index.obj.js。

创建云对象

一个空的云对象内容如下

// cloudfunctions/todo/index.obj.js
module.exports = {

}
复制代码
默认云对象模板是不包含任何方法的,我们为此对象添加一个add方法作为示例。

// cloudfunctions/todo/index.obj.js
module.exports = {
add: function(title = '', content = '') {
title = title.trim()
content = content.trim()
if(!title || !content) {
return {
errCode: 'INVALID_TODO',
errMsg: 'TODO标题或内容不可为空'
}
}
// ...其他逻辑,如操作todo数据表添加数据
return {
errCode: 0,
errMsg: '创建成功'
}
}
}
复制代码
至此云对象todo已经有了一个可以访问的方法了。接下来看如何使用客户端调用此云对象内的方法

客户端调用
客户端通过uniCloud.importObject方法获取云对象的实例,并可以通过此实例调用云对象内的方法。用法如下

const todo = uniCloud.importObject('todo')
const res = await todo.add('title demo', 'content demo')
复制代码
通过代码块cco可以快捷的输入以下代码:

const todo = uniCloud.importObject('todo')
复制代码
实际业务中需要考虑错误捕获,调用方式有两种:

try catch
const todo = uniCloud.importObject('todo')
try {
const res = await todo.add('title demo', 'content demo') //导入云对象后就可以直接调用该对象的方法了,注意使用异步await
console.log(res)
} catch (e) {
console.log(e.errCode)
console.log(e.errMsg)
}
复制代码
then catch(promise写法)
const todo = uniCloud.importObject('todo')
todo.add('title demo', 'content demo').then(res => {
console.log(res)
}).catch(e => {
console.log(e.errCode)
console.log(e.errMsg)
})
复制代码
importObject参数说明

interface ImportObjectOptions {
/**

  • 是否移除自动展示的ui
    */
    customUI?: boolean;
    /**
  • loading界面配置
    */
    loadingOptions?: ImportObjectLoadingOptions;
    /**
  • 错误提示配置
    */
    errorOptions?: ImportObjectErrorOptions;
    /**
  • 使用安全网络的方法及安全网络类型
    */
    secretMethods?: Record<string, 'none' | 'request' | 'response' | 'both'>;
    /**
  • 转化云对象内未捕获的错误或客户端网络错误
    */
    parseSystemError?: (params: ParseSystemErrorParams) => Promise<ParsedSystemError> | ParsedSystemError;
    }
    复制代码
    云对象的API
    云对象作为云函数的一种,可以调用所有node的API和uniCloud的API。

uniCloud有众多API,另见:uniCloud的API清单

除上述API之外,云对象的this对象还有一批专用方法来获取当前请求的上下文信息。

与云函数入参时的context不同,云对象没有context。它通过this对象挂载的几个内置方法来获取上下文信息。请注意开发者避免在this上挂载同名方法。

获取客户端信息
HBuilderX 3.4.9起此接口可获取所有客户端getSystemInfo返回的客户端信息,完整字段列表参考:getSystemInfo

接口形式

this.getClientInfo()

示例:

module.exports = {
add: function() {
const clientInfo = this.getClientInfo()
// clientInfo = {
// clientIP,
// appId,
// deviceId,
// source,
// //... 其他getSystemInfoSync返回值
// }
}
}
复制代码
返回值

getClientInfo返回的信息,是在客户端的uni.getSystemInfo的基础之上,增加了一些额外的信息。

除了getSystemInfo返回字段外,还包含以下信息

属性名 类型 说明
clientIP string 客户端ip
userAgent string 客户端ua,注意非本地运行环境下客户端getSystemInfoSync也会获取ua参数并上传给云对象,但是云对象会从http请求头里面获取ua而不是clientInfo里面的ua
source string 调用来源,返回值见下。HBuilderX 3.5.1+
requestId string 请求id。HBuilderX 3.5.1+
scene string 场景值。客户端uni.getLaunchOptionsSync返回的scene参数,新增于HBuilderX 3.5.1
getClientInfo().source,返回云函数调用来源,它的值域为:

取值 说明
client uni-app客户端导入云对象调用
function 由其他云函数或云对象调用
http 云对象URL化后通过http访问调用 HBuilderX 3.5.2+
timing 定时任务调用云对象 HBuilderX 3.5.2+
server 云函数上传并运行
注意事项

客户端上报的信息在理论上存在被篡改可能,实际业务中应验证前端传来的数据的合法性
除了clientIP外,其他客户端信息只有使用uni-app客户端以云对象的方式调用才能获取
云对象与云函数内获取客户端platform稍有不同,云函数未拉齐vue2、vue3版本app平台的platform值,vue2为app-plus,vue3为app。云对象无论客户端是vue2还是vue3,在app平台获取的platform均为app。这一点在使用uni-id时需要特别注意,详情见:uni-id文档 preferedAppPlatform
获取云端信息
接口形式

this.getCloudInfo()

示例

收起阅读 »

2

2

2

AI 一天开发一个 APP,为什么最后都死在审核?

AI 一天开发一个 APP,为什么最后都死在审核?

很多人觉得,现在有了 Cursor、Claude、ChatGPT,只要一句提示词,几个小时甚至一天时间,一个 APP 就能开发完成。

事实上,开发速度确实快了,但真正的问题并不在开发,而是在审核。

最近一年,我们接触了很多客户,他们都有一个共同特点:产品开发几乎没有花钱,却在审核阶段卡了一个月甚至几个月。有的苹果直接反馈 4.3(Spam),有的长期卡审核,还有的 Google Play、华为、小米等平台同样被拒。

为什么 AI 一天能开发一个 APP,最后却死在审核?今天结合我们这些年的上架经验,聊聊这个问题。

一、AI 能解决开发,却解决不了审核

很多开发者都有一个误区:APP 能运行,就意味着可以上架。实际上,这是两回事。

AI 擅长的是页面生成、功能实现、数据接口、UI 布局和 Bug 修复,但是审核平台真正关心的是:是否具有独立价值、是否属于重复应用、是否侵犯别人权益、是否符合隐私规范、是否存在误导用户、是否属于模板化产品。

这些内容,AI 并不会主动帮你考虑。所以很多项目虽然开发完成了,却还没有达到审核标准。

二、AI 写出来的代码,相似度远比你想象得高

很多人认为:我让 AI 每次重新生成代码,不就不一样了吗?

其实不是。AI 更喜欢输出成熟、稳定、经典的实现方式。例如页面结构几乎一致、组件命名十分相似、目录结构高度统一、网络请求封装类似、图片资源命名规律一致、公共组件大量重复。

如果几百个人都使用同一个模型开发同一种产品,那么生成出来的项目,整体结构就会越来越接近。代码虽然不是完全相同,但整体特征已经非常相似。

三、真正容易被检测的,并不仅仅是代码

很多人修改了几千行代码,结果还是收到 4.3。原因就在这里。

平台审核并不是只看代码,通常会综合分析很多内容,例如 UI 页面布局、APP 功能流程、图标 Icon、启动页、Bundle 信息、资源文件、文案描述、截图、权限申请、网络请求特征、账号信息等。

很多 AI 开发出来的项目,看似代码不同,但页面布局、交互流程、截图风格几乎一模一样,这也是很多项目容易进入人工审核的重要原因。

四、AI 最容易忽略的是产品定位

这是审核中最容易踩坑的一点。

很多人让 AI 写 Prompt:帮我生成一个记账 APP。AI 很快就能生成,但是为什么用户要下载你的产品?相比其他几十万个记账 APP,你有什么价值?你的特色是什么?

这些问题如果回答不了,那么平台很容易认为这是一个重复应用。苹果 4.3、Google Play 的 Repetitive Content,都比较关注这一点。

开发完成,不代表产品已经形成差异化。

五、AI 做出来的 UI,越来越像

这一点相信很多人都有体会。尤其是最近两年,很多 AI 默认生成卡片布局、渐变按钮、蓝紫色主题、圆角设计、底部 TabBar、Material 风格。

看起来很好看,但是几十万个 APP 都长这样。如果再加上相似功能,就很容易缺少辨识度。

六、审核真正审核的是产品,不是代码

很多开发者一直在改代码,其实审核人员更关心的是:这个产品有没有独立价值?是不是模板?是不是为了重复上架?是不是简单复制?是不是仅仅换了 Logo?

所以真正需要修改的是产品定位、功能逻辑、页面流程、用户价值、内容体系、商业模式,而不是一直修改变量名。

七、开发一天,上架可能一个月

这是很多独立开发者都会经历的事情。开发周期越来越短,审核周期反而越来越长。

我们见过不少项目:一天开发完成,两天完成测试,一个多月还在审核,连续收到 4.3、2.1、3.2 等反馈,最后不得不重新设计产品结构。

真正耗费时间的,往往不是开发,而是审核整改。

八、我们的经验:把审核前置,而不是审核后补救

这些年我们处理过大量上架案例,一个比较深的体会是:很多问题,如果等审核反馈后再改,成本会高得多。

更高效的做法,是在提交之前就从多个维度做检查,例如是否存在重复应用风险,页面和交互是否具备足够差异化,资源文件、图标、启动页是否过于相似,权限申请、隐私说明是否符合平台要求,元数据、截图、描述是否与产品实际功能一致。

提前发现问题,往往比收到拒审后再反复修改更节省时间。

写在最后

AI 正在改变 App 开发方式,让开发效率提升了一个数量级。但开发快,不代表审核也会变快。

平台审核的重点,从来不是这段代码是不是 AI 写的,而是你的产品是否真正具备独立价值、差异化体验,以及是否符合平台规则。

如果把 AI 当作开发工具,它能让你节省大量时间;但如果把 AI 当成一键上架工具,最后大概率会在审核阶段遇到各种问题。

开发只是开始,审核和合规,才是真正决定一个 App 能否成功上线的关键一步。

继续阅读 »

AI 一天开发一个 APP,为什么最后都死在审核?

很多人觉得,现在有了 Cursor、Claude、ChatGPT,只要一句提示词,几个小时甚至一天时间,一个 APP 就能开发完成。

事实上,开发速度确实快了,但真正的问题并不在开发,而是在审核。

最近一年,我们接触了很多客户,他们都有一个共同特点:产品开发几乎没有花钱,却在审核阶段卡了一个月甚至几个月。有的苹果直接反馈 4.3(Spam),有的长期卡审核,还有的 Google Play、华为、小米等平台同样被拒。

为什么 AI 一天能开发一个 APP,最后却死在审核?今天结合我们这些年的上架经验,聊聊这个问题。

一、AI 能解决开发,却解决不了审核

很多开发者都有一个误区:APP 能运行,就意味着可以上架。实际上,这是两回事。

AI 擅长的是页面生成、功能实现、数据接口、UI 布局和 Bug 修复,但是审核平台真正关心的是:是否具有独立价值、是否属于重复应用、是否侵犯别人权益、是否符合隐私规范、是否存在误导用户、是否属于模板化产品。

这些内容,AI 并不会主动帮你考虑。所以很多项目虽然开发完成了,却还没有达到审核标准。

二、AI 写出来的代码,相似度远比你想象得高

很多人认为:我让 AI 每次重新生成代码,不就不一样了吗?

其实不是。AI 更喜欢输出成熟、稳定、经典的实现方式。例如页面结构几乎一致、组件命名十分相似、目录结构高度统一、网络请求封装类似、图片资源命名规律一致、公共组件大量重复。

如果几百个人都使用同一个模型开发同一种产品,那么生成出来的项目,整体结构就会越来越接近。代码虽然不是完全相同,但整体特征已经非常相似。

三、真正容易被检测的,并不仅仅是代码

很多人修改了几千行代码,结果还是收到 4.3。原因就在这里。

平台审核并不是只看代码,通常会综合分析很多内容,例如 UI 页面布局、APP 功能流程、图标 Icon、启动页、Bundle 信息、资源文件、文案描述、截图、权限申请、网络请求特征、账号信息等。

很多 AI 开发出来的项目,看似代码不同,但页面布局、交互流程、截图风格几乎一模一样,这也是很多项目容易进入人工审核的重要原因。

四、AI 最容易忽略的是产品定位

这是审核中最容易踩坑的一点。

很多人让 AI 写 Prompt:帮我生成一个记账 APP。AI 很快就能生成,但是为什么用户要下载你的产品?相比其他几十万个记账 APP,你有什么价值?你的特色是什么?

这些问题如果回答不了,那么平台很容易认为这是一个重复应用。苹果 4.3、Google Play 的 Repetitive Content,都比较关注这一点。

开发完成,不代表产品已经形成差异化。

五、AI 做出来的 UI,越来越像

这一点相信很多人都有体会。尤其是最近两年,很多 AI 默认生成卡片布局、渐变按钮、蓝紫色主题、圆角设计、底部 TabBar、Material 风格。

看起来很好看,但是几十万个 APP 都长这样。如果再加上相似功能,就很容易缺少辨识度。

六、审核真正审核的是产品,不是代码

很多开发者一直在改代码,其实审核人员更关心的是:这个产品有没有独立价值?是不是模板?是不是为了重复上架?是不是简单复制?是不是仅仅换了 Logo?

所以真正需要修改的是产品定位、功能逻辑、页面流程、用户价值、内容体系、商业模式,而不是一直修改变量名。

七、开发一天,上架可能一个月

这是很多独立开发者都会经历的事情。开发周期越来越短,审核周期反而越来越长。

我们见过不少项目:一天开发完成,两天完成测试,一个多月还在审核,连续收到 4.3、2.1、3.2 等反馈,最后不得不重新设计产品结构。

真正耗费时间的,往往不是开发,而是审核整改。

八、我们的经验:把审核前置,而不是审核后补救

这些年我们处理过大量上架案例,一个比较深的体会是:很多问题,如果等审核反馈后再改,成本会高得多。

更高效的做法,是在提交之前就从多个维度做检查,例如是否存在重复应用风险,页面和交互是否具备足够差异化,资源文件、图标、启动页是否过于相似,权限申请、隐私说明是否符合平台要求,元数据、截图、描述是否与产品实际功能一致。

提前发现问题,往往比收到拒审后再反复修改更节省时间。

写在最后

AI 正在改变 App 开发方式,让开发效率提升了一个数量级。但开发快,不代表审核也会变快。

平台审核的重点,从来不是这段代码是不是 AI 写的,而是你的产品是否真正具备独立价值、差异化体验,以及是否符合平台规则。

如果把 AI 当作开发工具,它能让你节省大量时间;但如果把 AI 当成一键上架工具,最后大概率会在审核阶段遇到各种问题。

开发只是开始,审核和合规,才是真正决定一个 App 能否成功上线的关键一步。

收起阅读 »

1

1

1