对齐 Android SharePanelHelper 流程:H5 friendsSharetypeUrlToptitleDescript → 原生弹自定义面板(微信/QQ/抖音) → 按所选平台分享。 - common ShareEvents:SHOW_PANEL + SharePanelRequest/Result;ShareProvider 经一次性 resultEvent 与 entry 容器一对一解耦(双槽实例隔离,避免广播串扰) - ShareProvider 重构:微信走 SDK(type2 Canvas截图→WXImageObject / 其他→WXWebpageObject; scene 好友/朋友圈;回传 sharesuccess);QQ/抖音走 @kit.ShareKit 系统分享(文本/图片/链接/视频, 不集成对应 SDK、不回传);截图失败统一降级 - 截图:CapabilityContext.captureCanvas(WebSlot 用 controller.runJavaScript 取 canvas toDataURL,非激活/出错返回空);FileSystem.writeBytes 落盘;fileUri 给 WXImageObject/系统分享 - entry SharePanel 组件 + BridgeGameContainer 顶层叠加;重复面板/销毁均取消回投防 once 悬挂 真机验证项:微信开放平台注册后的真分享、系统分享面板拉起、canvas 截图 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
116 lines
4.0 KiB
Plaintext
116 lines
4.0 KiB
Plaintext
/**
|
|
* 文件系统工具(框架 §8.3 / 附录 A.4)。封装 @kit.CoreFileKit fileIo + resourceManager。
|
|
*
|
|
* 供 ResourceManager / AppDataInjector 使用:建目录、读写文本、递归删除、列目录、
|
|
* 把随包内置 rawfile(内置预置包 zip)拷贝到沙箱。纯原生内部 IO,H5 无感知。
|
|
*/
|
|
import { fileIo as fs } from '@kit.CoreFileKit';
|
|
import { resourceManager } from '@kit.LocalizationKit';
|
|
import { Logger } from 'common';
|
|
|
|
export class FileSystem {
|
|
private static readonly log: Logger = Logger.tag('FileSystem');
|
|
|
|
/** 路径是否存在。 */
|
|
static exists(path: string): boolean {
|
|
try {
|
|
return fs.accessSync(path);
|
|
} catch (e) {
|
|
const err = e as Error;
|
|
FileSystem.log.w(`accessSync(${path}) failed: ${err.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/** 递归创建目录(已存在则忽略)。 */
|
|
static ensureDir(path: string): void {
|
|
if (FileSystem.exists(path)) {
|
|
return;
|
|
}
|
|
fs.mkdirSync(path, true);
|
|
}
|
|
|
|
/** 递归删除文件或目录(不存在/竞态则忽略,绝不抛错——对齐注释承诺)。 */
|
|
static rmrf(path: string): void {
|
|
if (!FileSystem.exists(path)) {
|
|
return;
|
|
}
|
|
try {
|
|
const stat: fs.Stat = fs.statSync(path);
|
|
if (stat.isDirectory()) {
|
|
fs.rmdirSync(path);
|
|
} else {
|
|
fs.unlinkSync(path);
|
|
}
|
|
} catch (e) {
|
|
const err = e as Error;
|
|
FileSystem.log.w(`rmrf(${path}) ignored: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
/** 重命名/移动(同文件系统)。用于资源原子换入。 */
|
|
static rename(oldPath: string, newPath: string): void {
|
|
fs.renameSync(oldPath, newPath);
|
|
}
|
|
|
|
/** 写文本(覆盖;自动建父目录)。 */
|
|
static writeText(path: string, content: string): void {
|
|
FileSystem.ensureDir(FileSystem.dirOf(path));
|
|
const file: fs.File = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC);
|
|
try {
|
|
fs.writeSync(file.fd, content);
|
|
} finally {
|
|
fs.closeSync(file);
|
|
}
|
|
}
|
|
|
|
/** 写二进制(覆盖;自动建父目录)。用于截图分享落盘等。 */
|
|
static writeBytes(path: string, bytes: Uint8Array): void {
|
|
FileSystem.ensureDir(FileSystem.dirOf(path));
|
|
const file: fs.File = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC);
|
|
try {
|
|
// 按实际视图(byteOffset/byteLength)写入,避免底层 buffer 为大池子视图时写多余字节
|
|
const view: ArrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;
|
|
fs.writeSync(file.fd, view);
|
|
} finally {
|
|
fs.closeSync(file);
|
|
}
|
|
}
|
|
|
|
/** 读文本(不存在返回空串)。 */
|
|
static readText(path: string): string {
|
|
if (!FileSystem.exists(path)) {
|
|
return '';
|
|
}
|
|
return fs.readTextSync(path);
|
|
}
|
|
|
|
/** 列目录条目名(不存在返回空数组)。 */
|
|
static listDir(path: string): string[] {
|
|
if (!FileSystem.exists(path)) {
|
|
return [];
|
|
}
|
|
return fs.listFileSync(path);
|
|
}
|
|
|
|
/** 把随包内置 rawfile 拷贝到沙箱目标路径(用于内置预置包 zip)。 */
|
|
static copyRawFileTo(resMgr: resourceManager.ResourceManager, rawFilePath: string, destPath: string): void {
|
|
const bytes: Uint8Array = resMgr.getRawFileContentSync(rawFilePath);
|
|
FileSystem.ensureDir(FileSystem.dirOf(destPath));
|
|
const file: fs.File = fs.openSync(destPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC);
|
|
try {
|
|
// 按 Uint8Array 的实际视图(byteOffset/byteLength)写入,避免底层 buffer 为大池子视图时写入多余字节致 zip 损坏
|
|
const view: ArrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;
|
|
fs.writeSync(file.fd, view);
|
|
} finally {
|
|
fs.closeSync(file);
|
|
}
|
|
}
|
|
|
|
/** 取父目录路径(无分隔符则返回原串)。 */
|
|
static dirOf(path: string): string {
|
|
const idx: number = path.lastIndexOf('/');
|
|
return idx > 0 ? path.substring(0, idx) : path;
|
|
}
|
|
}
|