HarmonyOS NEXT应用开发,两天上架一百个鸿蒙元服务(暴富梦破碎,失败的教训总结)
2024年的最后一个季度,华为鸿蒙系统推出了一个令人兴奋的开发者激励计划,上架一个元服务就能获得1200元的奖励。对于许多开发者来说,这无疑是一个将“创意”转化为“财富”的绝佳机会。当我看到这个计划的时候,心中也涌现出一股“捡钱”的冲动。我心想,制作一个元服务只需要不到十分钟,那么一百个元服务岂不是能大赚一笔?于是,我开始了我的“鸿蒙元服务”之旅。
去年年底的一阵子,周末两天上架了一百个鸿蒙元服务,最后竟全部被拒了。且被“杀一儆百”,凡是鸿蒙应用市场上的诗词类元服务全部被毙,其他人的也受到牵连。这里反思总结下,做对了什么错了什么。投机取巧并不可取,做事还是要脚踏实地。虽然失败了,但经验教训值得反思,特此总结。
这里还是推荐下鸿蒙系统开发,比起android简单太多。之前开发过Android智能终端,总是烦人的XML布局和databinding,及混杂的Kotlin与Java代码。而鸿蒙系统的出现是新的曙光。鸿蒙系统以其简单易用的开发环境和强大的创新体验,极大地简化了开发流程,大大提升了开发效率。
尽管如此,开源鸿蒙系统OpenHarmony,却仍处于发展初期,资源相对匮乏。市面上成熟的开发板不多,这也给想要基于OpenHarmony进行硬件国产化的开发者带来了不小困扰。身边的硬件工程师朋友,虽有心尝试,却被资源稀缺和开发环境不成熟所困扰,陷入到想用而不敢用的尴尬境地。一套开发板卖一千多块,乖乖嘞,让不少玩家望而止步。
既然目标已定,我便迅速找到了一个可以批量生成元服务的素材——唐宋元明清各个朝代的诗词。我的想法很简单,只需更换不同的logo图标和诗词内容,就能生成一个个新的元服务。为了提高效率,我编写了一个Python脚本,主要用于分发logo图片和打包工程,还实现了自动化打包和自动根据1024位图生成元服务logo图标,部署了个golang后台服务接口,用来根据传递的名称获取隐私政策声明。
我的路子是数据导向,根据sql语句查询出从商到清代的上万条数据,每200条产生一个data.json1,data.json2,data.json3…等数据文件。然后再使用脚本自动创建生成工程目录prj_1,prj_2,依次类推。并把对应的json文件拷贝到工程对应目录,分发logo图片到各个工程目录。这样工程模板和数据齐全啦。
这样,我只需在每一步操作中运行脚本,就能大大减少手动重复工作的时间。为了更快地完成任务,我还雇佣了几位郑州轻工业大学的美女学生,让他们帮助我通过网页操作来完成上架流程。
import sqlite3
import json
# 连接到 SQLite 数据库
connection = sqlite3.connect('poemsdb')
cursor = connection.cursor()
# 查询表中所需的字段,先搞个10条数据吧
query = """
SELECT Author, Title, Content, Intro, Comment, Translation, Annotation
FROM poem
WHERE Dynasty IN ('商', '周', '晋', '南北朝', '五代十国', '唐', '宋', '元', '明', '清')
AND kind IN ('诗','词')
AND Intro != 'None'
AND Intro != ''
"""
cursor.execute(query)
# 获取结果
rows = cursor.fetchall()
# 构建一个字典列表以便转换为 JSON
poets_data = []
file_counter = 1
for row in rows:
if len(row[2]) <= 0:
continue
poet_data = {
"poet": row[0],
"title": row[1],
"content": row[2],
"intro": row[3],
"comment": row[4],
"trans": row[5],
"annot": row[6]
}
poets_data.append(poet_data)
# 每隔200条数据写入一个 JSON 文件
if len(poets_data) == 200:
json_filename = f'data.json{file_counter}'
with open(json_filename, 'w', encoding='utf-8') as json_file:
json.dump(poets_data, json_file, ensure_ascii=False, indent=4)
print(f"已写入文件: {json_filename}")
# 清空列表以存储下一批数据
poets_data.clear()
file_counter += 1
# 处理剩余的数据,如果有的话
if poets_data:
json_filename = f'data.json{file_counter}'
with open(json_filename, 'w', encoding='utf-8') as json_file:
json.dump(poets_data, json_file, ensure_ascii=False, indent=4)
print(f"已写入文件: {json_filename}")
# 关闭数据库连接
cursor.close()
connection.close()
print("所有数据已成功提取并写入 JSON 文件。")
刚开始的几天,一切似乎都在按计划进行,我的元服务接连通过审核,上架到鸿蒙应用市场。然而好景不长,随着越来越多的诗词类元服务被提交,最终的结果却出乎意料。刚开始时,几个元服务还能够顺利通过,但很快,华为方面似乎对这种批量提交的诗词类元服务产生了反感,审核速度明显放慢,而且有越来越多的服务被直接否决。提示“您的元服务欠缺创意性和独特价值,未能为用户提供差异化的体验,不符合华为应用市场《元服务审核指南》第3.4项。”
甚至包括那些别人已经上架超过七天并且已经邮件通知获得激励的元服务,也被误伤被迫下架了。明显,负责审核上架的人,被这波上百个诗词文化冲击,产生了严重的审美疲劳,被惹怒了。这突然的转变,无疑让我的“捡钱梦”破灭了,如果,如果能够上架十几个的时候见好就收…,如果当初不太贪。可惜没有如果,两天的周末时间也都白费了。
自动生成logo脚本:
# 使用说明
# 1. 安装PIL库,使用pip install pillow安装
# 2. 将icon.py文件放到 [ 项目目录,注意根目录下 ] 目录下,如 TangShi 项目目录,该目录下为 各个 开发项目
# 3. 打开项目,手动替换 "AppScope
esourcesaseelementstring.json" 对应app 名称,以及 元服务图片生成
# 4. 在目录下运行 icon.py 文件,会在对应目录下生成 icon.png、startIcon.png 以及 EntryCard 图片
# 5. 正常打包项目
import os
import shutil
import json
from PIL import Image,ImageDraw,ImageFont
def merge_images(app_icon, temp_icon, output_ec_icon,app_name):
# 打开图片
image_icon = Image.open(app_icon)
image_temp_icon = Image.open(temp_icon)
#Image.open(temp_icon)
resized_image = image_icon.resize((80,80))
#resized_image.save("rtemp.png")
smaller_image = image_temp_icon.crop((30,2,110,82));
#smaller_image.save("stemp.png")
image_process = Image.new('RGBA', (80,80))
print(resized_image.size)
print(smaller_image.size)
image_process = Image.alpha_composite(image_process,smaller_image.convert('RGBA'))
image_process = Image.alpha_composite(image_process,resized_image.convert('RGBA'))
#new_image.save('temp.png')
image_result = Image.new('RGBA', (140,140))
image_result.paste(image_temp_icon, (0, 0))
image_result.paste(image_process, (30, 2))
draw = ImageDraw.Draw(image_result)
font = ImageFont.truetype('simhei.ttf', 14)
draw.text(((140-len(app_name)*14)/2,88),app_name,font=font,fill=(36,54,71))
image_result.save(output_ec_icon)
# 名称处理
def write_string(app_name,tag):
entry_string_url = "entrysrcmain
esources"+ tag +"elementstring.json"
esurl = os.path.join(current_dir,entry_string_url)
print('string 目录: ', esurl)
with open(esurl, 'r',encoding='utf-8') as f:
sdata = json.load(f)
for d in sdata['string']:
if d['name'] == 'EntryAbility_label':
d['value'] = app_name
elif d['name'] == 'entrance_desc':
d['value'] = app_name
elif d['name'] == 'entrance_display_name':
d['value'] = app_name
# 将修改后的数据写回 JSON 文件
with open(esurl, 'w',encoding='utf-8') as file:
json.dump(sdata, file, indent=4,ensure_ascii=False)
print( tag +' string 修改成功')
# 原始 PNG 图片路径
current_dir = os.getcwd()
print('当前目录: ', current_dir)
source_png_path = "AppScope
esourcesasemediapp_icon.png"
# 目标目录
target_dir = "entrysrcmain
esourcesasemedia"
target_icon= "icon.png"
target_startIcon= "startIcon.png"
# app名称
app_name_url = "AppScope
esourcesaseelementstring.json"
with open(os.path.join(current_dir, app_name_url), 'r',encoding='utf-8') as f:
sdata = json.load(f)
app_name = sdata['string'][0]["value"]
print('应用程序名称:', app_name)
sp= os.path.join(current_dir,source_png_path)# 复制文件
print('原始目录: ', sp)
#复制文件
shutil.copy(sp, target_dir + target_icon)
shutil.copy(sp, target_dir + target_startIcon)
print('复制成功')
#处理 EntryCard
ec_url = "EntryCardentryasesnapshotentrance-2x2.png"
tmp_url = os.path.join(current_dir,"..","template.png")
merge_images(sp, tmp_url,ec_url,app_name)
#修改 string.json 文件
write_string(app_name,"base")
write_string(app_name,"en_US")
write_string(app_name,"zh_CN")
# 打包
clearn ="hvigorw -p product=default clean --analyze=normal --parallel --incremental --daemon"
os.system(clearn)
print('清理成功')
cmd="hvigorw --mode project -p product=default assembleApp --analyze=normal --parallel --incremental --daemon"
os.system(cmd)
print('打包成功')
b_path =os.path.join(current_dir,"buildoutputsdefault")
b_name = os.path.basename(current_dir) + "-default-signed.app"
#把app_icon文件也复制过去
sp= os.path.join(current_dir,"app_icon.png")# 复制文件
shutil.copy(sp, os.path.join( b_path,"app_icon.png"))
print('复制成功')
os.system(f'explorer /select , { os.path.join( b_path,b_name)}')
print('打开输出目录:' + b_path)
print('输出文件名:' + b_name)
经过这次失败,我深刻体会到了急功近利的弊端。虽然最终没有获得预期的奖励,但这次经历也并非毫无价值。至少我在短时间内摸熟了鸿蒙系统的应用签名、编译打包和上架流程,这对于我今后开发鸿蒙应用来说,无疑是一笔财富。
人生的意义不在于等待,而在于行动。
太多人整天想着做某事,却迟迟没有付诸行动。为什么一定要等到万事俱备再出发呢?实际上,你永远不可能做到100%的准备。因此,只有先勇敢地迈出第一步,不断地实践和改进,才能真正地收获成功。
对于鸿蒙的开发,我总结出以下几个点:
- 高目标牵引:设定一个远大的目标,这将促使你不断努力,追求卓越。
- 目标拆解为可实现的小目标:将大目标拆解成一系列小目标,一步一步地去实现。
- 热爱是做好事情的前提:只有对某件事充满热爱,才能投入更多的情感和精力,从而做得更好。
- 复盘总结:无论成败,都要进行复盘总结,找出问题所在,思考改进的方法。
如果,不对世界做出些什么,就会很无趣!
这世间的很多人都是这样,总是困于想,而懒于行。
想出去旅游的时候,总是对自己说,等天气好了再去;
想学习一项新的技能,又总是推迟,总想等有充足的时间了再去学。
可是你有没有问过自己:
为什么一定要准备好再出发呢?
你永远不可能做好100%的准备啊。
任何一件事情,你只有先投入进去,然后再不断改进,才能有所收获。
人生的主动权永远在于选择踏上某条路,而不是等待某条路自动变得平坦。
人生就像一场漫长的旅行,我们不能只停留在想象和规划阶段,而是要勇敢地迈出第一步。
种一棵树最好的时间是十年前,其次是现在。
不行动,我们的生活将变得索然无味。因此,别再等待了。从现在开始,给自己定一个小目标,行动起来吧,做一个行动派!