M3(批5): AudioProvider 播放 + 七牛上传器(@qiniu/upload)

依赖:ohpm i @qiniu/upload@1.0.2(platform)

platform QiniuUploader:UploadFile.fromPath + key + createMultipartUploadV2Task(context,file,{tokenProvider})。
  🔴 token 走 tokenProvider(服务端用 AK/SK 生成 uploadToken(bucket)),AK/SK 不入端——纠正原 Android 硬编码 AK/SK

T-M3-10 AudioProvider(@kit.MediaKit AVPlayer):
  - mediaTypeAudio:播放语音 url → gameui_play_voice/gameui_stop_voice(user 透传)
  - srcIsloop:播放本地 wav(<gameDir>/assets/wav/<src>,isloop 0一次/>0循环/<0停止)
  - voicePlaying:静音总开关 setVolume
  - prepareaudio:录音分档(QiniuUploader 链路就绪;按住说话手势+麦克风+七牛服务端 token 三依赖未就绪前安全空实现)

bucket/域名/key 规则对齐原工程(bucket gameauio、回放 http://gameaudio.daoqi88.cn/<key>,由服务端 token 与 AudioProvider 接入时落地)
devecocli build 通过(CompileArkTS 编译七牛/音频无误)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lanterngamescn
2026-06-25 20:14:02 +08:00
parent 829f267966
commit 4a8524bcbe
10 changed files with 261 additions and 7 deletions
@@ -0,0 +1,46 @@
/**
* 七牛云对象存储上传(@qiniu/upload,契约 §10.6 录音上传)。
*
* 🔴 安全(CLAUDE.md 附录 B / §14.2):上传 token 由 **tokenProvider 异步提供**
* 应由服务端用 AK/SK 生成 uploadToken(bucket) 后下发;**AK/SK 绝不入客户端**。
* 原 Android 把 AK/SK 硬编码在端侧,本平台用 tokenProvider 模式纠正。
*/
import { common } from '@kit.AbilityKit';
import { createMultipartUploadV2Task, UploadFile, UploadConfig, UploadTask } from '@qiniu/upload';
import { Logger } from 'common';
/** token 提供器:返回上传 token 的 Promise(来源应为服务端)。 */
export type QiniuTokenProvider = () => Promise<string>;
export class QiniuUploader {
private static readonly log: Logger = Logger.tag('QiniuUploader');
/**
* 上传本地文件到七牛,资源名为 key。成功返回 true。
* @param context UIAbility 上下文
* @param localPath 本地文件路径
* @param key 七牛资源名(= 回放 URL 的路径段)
* @param tokenProvider 上传 token 提供器(服务端生成 uploadToken(bucket)
*/
static async upload(context: common.Context, localPath: string, key: string,
tokenProvider: QiniuTokenProvider): Promise<boolean> {
const file: UploadFile = UploadFile.fromPath(localPath);
file.key = key;
const config: UploadConfig = { tokenProvider };
const task: UploadTask = createMultipartUploadV2Task(context, file, config);
let failed: boolean = false;
task.onError(() => {
failed = true;
});
try {
await task.start();
} catch (e) {
QiniuUploader.log.w(`upload start failed: ${(e as Error).message}`);
return false;
}
if (failed) {
QiniuUploader.log.w(`upload failed for key=${key}`);
}
return !failed;
}
}