refactor(config): 七牛/微信密钥外置——AK/SK+微信AppID 入本地 app_config, domain/bucket 走远程配置

- app_config.json + AppConfig: qiniu_access_key/qiniu_secret_key/wechat_app_id/wechat_app_secret(扁平snake_case)
- RemoteConfig.VersionFields + audio_domain/audio_bucket(4层可携带), VersionDecision + audioDomain/audioBucket
- VersionResolver.resolve 复用 pickStr 解析 audioDomain/audioBucket(4层逐级回退)
- QiniuToken.uploadToken(accessKey,secretKey,bucket) 改传参,去掉硬编码常量
- AudioProvider.doUpload: AK/SK取本地配置, domain/bucket取远程配置(cfg.resolve), URL用远程domain
- WeChatApi.configure(appId) 注入AppID(去WX_APP_ID常量), EntryAbility.onCreate 从配置注入
- 更新 QiniuToken 单测传参

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lanterngamescn
2026-06-27 19:12:43 +08:00
co-authored by Claude Opus 4.8
parent e5d8eeb3b1
commit c39d8eb400
10 changed files with 85 additions and 28 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ export { AmrRecorder } from './src/main/ets/providers/AmrRecorder';
export { NavProvider } from './src/main/ets/providers/NavProvider';
// 微信 SDK 封装(EntryAbility 处理回调 want 需用)
export { WeChatApi, WX_APP_ID } from './src/main/ets/wx/WeChatApi';
export { WeChatApi } from './src/main/ets/wx/WeChatApi';
// 分享文本拼接纯函数(供单测)
export { buildShareText } from './src/main/ets/share/ShareText';
@@ -23,7 +23,7 @@ import { common, abilityAccessCtrl } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
import { BridgeController } from 'feature_bridge';
import { InboundHandlers, OutboundHandlers, MediaTypeAudioReq, SrcIsLoopReq, GetAudioUrlResp } from 'contracts';
import { ConfigManager, ResourceManager } from 'domain_resource';
import { ConfigManager, ResourceManager, VersionDecision, AppConfig } from 'domain_resource';
import { FileSystem, QiniuUploader, QiniuToken } from 'platform';
import { Logger, EventBus, EventPayload, AudioEvents, ShowRecordingRequest, RecordResult } from 'common';
import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider';
@@ -406,11 +406,23 @@ export class AudioProvider implements CapabilityProvider {
private async doUpload(filePath: string, key: string, timeSec: number): Promise<void> {
const ctx: common.UIAbilityContext | undefined = this.context;
if (ctx === undefined || filePath === '') {
const cfg: ConfigManager | undefined = this.config;
if (ctx === undefined || cfg === undefined || filePath === '') {
return; // 已发过空回投(reset 语义);上传不了则保持"无语音"
}
try {
const token: string = await QiniuToken.uploadToken();
// AK/SK 取本地 app_configdomain/bucket 取远程配置(audio_domain/audio_bucket4 层回退)。
const local: AppConfig = cfg.getLocal();
const ak: string = local.qiniuAccessKey;
const sk: string = local.qiniuSecretKey;
const decision: VersionDecision = await cfg.resolve();
const bucket: string = decision.audioBucket;
const domain: string = decision.audioDomain;
if (ak === '' || sk === '' || bucket === '' || domain === '') {
this.log.w(`qiniu config missing: ak/sk(local) ok=${ak !== '' && sk !== ''}, bucket='${bucket}' domain='${domain}'(remote)`);
return;
}
const token: string = await QiniuToken.uploadToken(ak, sk, bucket);
const ok: boolean = await QiniuUploader.upload(ctx, filePath, key, () => Promise.resolve(token));
try {
fileIo.unlinkSync(filePath);
@@ -418,7 +430,7 @@ export class AudioProvider implements CapabilityProvider {
this.log.w(`cleanup uploaded file failed: ${(e as Error).message}`);
}
if (ok) {
this.emitAudioUrl(`http://gameaudio.daoqi88.cn/${key}`, timeSec);
this.emitAudioUrl(`http://${domain}/${key}`, timeSec);
} else {
this.log.w(`qiniu upload failed key=${key}`); // 已发空回投,不再重复
}
@@ -10,26 +10,35 @@ import {
} from '@tencent/wechat_open_sdk';
import { Logger } from 'common';
/** 微信 AppID(公开标识,契约 §13)。 */
export const WX_APP_ID: string = 'wxd2bd650e06bdfe58';
export type AuthRespCallback = (resp: SendAuthResp) => void;
export class WeChatApi {
private static readonly log: Logger = Logger.tag('WeChatApi');
private static inst: WeChatApi | undefined = undefined;
/** 微信 AppID(从本地 app_config.wechat_app_id 注入;须在首次 getInstance 前 configure)。 */
private static appId: string = '';
private readonly api: WXApi;
private readonly handler: WXApiEventHandler;
private authCb: AuthRespCallback | undefined = undefined;
private constructor() {
this.api = WXAPIFactory.createWXAPI(WX_APP_ID);
this.api = WXAPIFactory.createWXAPI(WeChatApi.appId);
this.handler = {
onReq: (_req: BaseReq) => { },
onResp: (resp: BaseResp) => this.routeResp(resp),
};
}
/**
* 注入微信 AppID(来自本地 app_config,不再硬编码)。须在首次 getInstance() 之前调用,
* 通常在 EntryAbility.onCreate 处理微信回调 want 之前。空串/重复 configure 安全。
*/
static configure(appId: string): void {
if (appId !== '') {
WeChatApi.appId = appId;
}
}
static getInstance(): WeChatApi {
if (WeChatApi.inst === undefined) {
WeChatApi.inst = new WeChatApi();