|
|
@@ -2,7 +2,7 @@ import { hilog } from '@kit.PerformanceAnalysisKit';
|
|
|
import { formProvider, formBindingData } from '@kit.FormKit';
|
|
|
import { preferences } from '@kit.ArkData';
|
|
|
import { Context } from '@kit.AbilityKit';
|
|
|
-import { WidgetData, FormattedWidgetData, WidgetSize } from './WidgetTypes';
|
|
|
+import { WidgetData, FormattedWidgetData, WidgetSize, ImageFileInfo } from './WidgetTypes';
|
|
|
import { FormLayoutManager } from './FormLayoutManager';
|
|
|
import { PreferencesUtil } from '../utils/PreferencesUtil';
|
|
|
import { GlobalWidgetManager } from './GlobalWidgetManager';
|
|
|
@@ -54,6 +54,22 @@ interface ImageCacheItem {
|
|
|
fileSize: number;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 包含图片文件描述符的卡片数据接口
|
|
|
+ */
|
|
|
+interface FormattedWidgetDataWithImages extends FormattedWidgetData {
|
|
|
+ formImages?: Record<string, number>;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 处理后的本地图片信息接口
|
|
|
+ */
|
|
|
+interface ProcessedImageInfo {
|
|
|
+ fileName: string;
|
|
|
+ memoryUri: string;
|
|
|
+ fd: number;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* 更新统计接口
|
|
|
*/
|
|
|
@@ -118,7 +134,7 @@ export class EnhancedFormUpdateService {
|
|
|
*/
|
|
|
public setAppContext(context: Context): void {
|
|
|
this.appContext = context;
|
|
|
- hilog.info(0x0000, TAG, '🎯 App context set for EnhancedFormUpdateService');
|
|
|
+
|
|
|
this.initializeImageCache();
|
|
|
}
|
|
|
|
|
|
@@ -127,6 +143,10 @@ export class EnhancedFormUpdateService {
|
|
|
*/
|
|
|
public async updateAllForms(data: WidgetData): Promise<BatchUpdateStats> {
|
|
|
const batchStartTime = Date.now();
|
|
|
+ console.log("Heanup updateAllForms data:"+JSON.stringify(data))
|
|
|
+
|
|
|
+ // 预处理图片路径 - 转换本地文件URI为可用格式
|
|
|
+ const processedData = await this.preprocessImageData(data);
|
|
|
|
|
|
try {
|
|
|
if (!this.appContext) {
|
|
|
@@ -137,53 +157,63 @@ export class EnhancedFormUpdateService {
|
|
|
// 防抖检查
|
|
|
const now = Date.now();
|
|
|
if (now - this.lastUpdateTime < this.updateDebounceDelay) {
|
|
|
- hilog.info(0x0000, TAG, `⏭️ Update debounced, skipping (${now - this.lastUpdateTime}ms since last update)`);
|
|
|
+
|
|
|
return this.createEmptyStats();
|
|
|
}
|
|
|
|
|
|
// 防止并发更新
|
|
|
if (this.isUpdating) {
|
|
|
- hilog.warn(0x0000, TAG, '⚠️ Update already in progress, skipping this request');
|
|
|
+
|
|
|
return this.createEmptyStats();
|
|
|
}
|
|
|
|
|
|
this.isUpdating = true;
|
|
|
this.lastUpdateTime = now;
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `🚀 Starting enhanced batch form update: isPlaying=${data.playState.isPlaying}, title="${data.currentSong.title}"`);
|
|
|
+
|
|
|
|
|
|
// 获取所有持久化的 Form ID(使用原有方法)
|
|
|
const prefs = await this.preferencesUtil.getPreferences(this.appContext);
|
|
|
const formIds = await this.preferencesUtil.getFormIds(prefs);
|
|
|
|
|
|
if (formIds.length === 0) {
|
|
|
- hilog.info(0x0000, TAG, '📋 No forms found in persistence, skipping update');
|
|
|
+
|
|
|
return this.createEmptyStats();
|
|
|
}
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `📋 Found ${formIds.length} forms to update: [${formIds.join(', ')}]`);
|
|
|
+
|
|
|
|
|
|
// 验证活跃卡片与持久化卡片的一致性
|
|
|
await this.validateActiveWidgets(formIds, prefs);
|
|
|
+
|
|
|
+ // 预先验证卡片ID的有效性,移除无效的ID
|
|
|
+ const validFormIds = await this.preValidateFormIds(formIds, prefs);
|
|
|
+
|
|
|
+ if (validFormIds.length === 0) {
|
|
|
+ hilog.warn(0x0000, TAG, '📋 No valid form IDs found after validation');
|
|
|
+ return this.createEmptyStats();
|
|
|
+ }
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `📋 Valid forms: ${validFormIds.length}/${formIds.length}`);
|
|
|
|
|
|
// 并行更新所有卡片
|
|
|
- const updatePromises = formIds.map((formId, index) => {
|
|
|
- hilog.info(0x0000, TAG, `🎯 Creating update task ${index + 1}/${formIds.length} for form: ${formId}`);
|
|
|
- hilog.info(0x0000, TAG, "更新的卡片数据: "+JSON.stringify(data));
|
|
|
- return this.updateSingleFormWithRetry(formId, data, prefs);
|
|
|
+ const updatePromises = validFormIds.map((formId, index) => {
|
|
|
+
|
|
|
+
|
|
|
+ return this.updateSingleFormWithRetry(formId, processedData, prefs);
|
|
|
});
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `⏳ Executing ${updatePromises.length} parallel update tasks...`);
|
|
|
+
|
|
|
|
|
|
// 等待所有更新完成
|
|
|
const results = await Promise.allSettled(updatePromises);
|
|
|
|
|
|
// 处理结果并生成统计信息
|
|
|
- const batchStats = this.processBatchResults(formIds, results, batchStartTime);
|
|
|
+ const batchStats = this.processBatchResults(validFormIds, results, batchStartTime);
|
|
|
|
|
|
// 清理无效的 Form ID
|
|
|
if (batchStats.failed > 0) {
|
|
|
- await this.cleanupInvalidForms(prefs, formIds, results);
|
|
|
+ await this.cleanupInvalidForms(prefs, validFormIds, results);
|
|
|
}
|
|
|
|
|
|
// 更新统计信息
|
|
|
@@ -198,7 +228,7 @@ export class EnhancedFormUpdateService {
|
|
|
(this.updateStats.averageUpdateTime * (this.updateStats.totalUpdates - batchStats.total) + batchStats.averageUpdateTime * batchStats.total) / this.updateStats.totalUpdates;
|
|
|
}
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `✅ Batch update completed: ${batchStats.success}/${batchStats.total} successful in ${batchStats.duration}ms (avg: ${batchStats.averageUpdateTime.toFixed(1)}ms per form)`);
|
|
|
+
|
|
|
|
|
|
return batchStats;
|
|
|
|
|
|
@@ -221,14 +251,14 @@ export class EnhancedFormUpdateService {
|
|
|
try {
|
|
|
if (attempt > 0) {
|
|
|
const delay = this.retryDelays[Math.min(attempt - 1, this.retryDelays.length - 1)];
|
|
|
- hilog.info(0x0000, TAG, `🔄 [${formId}] Retry attempt ${attempt}/${this.maxRetryCount} after ${delay}ms delay`);
|
|
|
+
|
|
|
await this.sleep(delay);
|
|
|
}
|
|
|
|
|
|
await this.updateSingleForm(formId, data, prefs);
|
|
|
|
|
|
const updateTime = Date.now() - startTime;
|
|
|
- hilog.info(0x0000, TAG, `✅ [${formId}] Update successful on attempt ${attempt + 1} (${updateTime}ms)`);
|
|
|
+
|
|
|
|
|
|
return {
|
|
|
formId,
|
|
|
@@ -239,7 +269,35 @@ export class EnhancedFormUpdateService {
|
|
|
|
|
|
} catch (error) {
|
|
|
lastError = error as Error;
|
|
|
- hilog.warn(0x0000, TAG, `⚠️ [${formId}] Update attempt ${attempt + 1} failed: ${lastError.message}`);
|
|
|
+ const errorStr :string= error.toString();
|
|
|
+
|
|
|
+ // 如果是无效卡片ID错误,立即停止重试并清理
|
|
|
+ if (errorStr.includes('form not exist') ||
|
|
|
+ errorStr.includes('16501001') ||
|
|
|
+ errorStr.includes('The ID of the form to be operated does not exist')) {
|
|
|
+ hilog.warn(0x0000, TAG, `🗑️ [${formId}] Invalid form ID detected, cleaning up immediately`);
|
|
|
+
|
|
|
+ // 立即清理无效ID
|
|
|
+ try {
|
|
|
+ await this.preferencesUtil.removeFormId(prefs, formId);
|
|
|
+ this.globalWidgetManager.unregisterWidget(formId);
|
|
|
+ hilog.info(0x0000, TAG, `🗑️ [${formId}] Cleaned up invalid form ID`);
|
|
|
+ } catch (cleanupError) {
|
|
|
+ hilog.error(0x0000, TAG, `❌ [${formId}] Failed to cleanup invalid form ID: ${cleanupError}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 立即返回失败结果,不再重试
|
|
|
+ const updateTime = Date.now() - startTime;
|
|
|
+ return {
|
|
|
+ formId,
|
|
|
+ success: false,
|
|
|
+ error: lastError,
|
|
|
+ updateTime,
|
|
|
+ retryCount: attempt
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -260,14 +318,14 @@ export class EnhancedFormUpdateService {
|
|
|
*/
|
|
|
private async updateSingleForm(formId: string, data: WidgetData, prefs: preferences.Preferences): Promise<void> {
|
|
|
try {
|
|
|
- hilog.info(0x0000, TAG, `🎯 [${formId}] Starting enhanced form update...`);
|
|
|
+
|
|
|
|
|
|
// 获取卡片的当前状态
|
|
|
const formState = await this.preferencesUtil.getFormState(prefs, formId);
|
|
|
const widgetSizeStr = (formState?.size as string) || 'medium';
|
|
|
const widgetSize: WidgetSize = widgetSizeStr as WidgetSize;
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `🎯 [${formId}] Widget size: ${widgetSizeStr}`);
|
|
|
+
|
|
|
|
|
|
// 适配数据到卡片尺寸
|
|
|
const adaptedData = this.layoutManager.adaptDataForSize(data, widgetSize);
|
|
|
@@ -296,13 +354,48 @@ export class EnhancedFormUpdateService {
|
|
|
imgName: adaptedData.imgName || ''
|
|
|
};
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `🎯 [${formId}] Formatted data prepared: isPlaying=${formattedData.isPlaying}, title="${formattedData.songTitle}"`);
|
|
|
+
|
|
|
|
|
|
- // 创建 FormBindingData 并更新卡片
|
|
|
- const formData = formBindingData.createFormBindingData(formattedData);
|
|
|
+ // 处理图片文件描述符(如果有本地图片)
|
|
|
+ let formData: formBindingData.FormBindingData;
|
|
|
+ if (data.imageFileInfo && formattedData.imgName) {
|
|
|
+ // 创建包含文件描述符的数据
|
|
|
+ const dataWithImages: FormattedWidgetDataWithImages = {
|
|
|
+ isPlaying: formattedData.isPlaying,
|
|
|
+ isPaused: formattedData.isPaused,
|
|
|
+ isLoading: formattedData.isLoading,
|
|
|
+ songTitle: formattedData.songTitle,
|
|
|
+ songArtist: formattedData.songArtist,
|
|
|
+ songAlbum: formattedData.songAlbum,
|
|
|
+ coverImage: formattedData.coverImage,
|
|
|
+ currentTime: formattedData.currentTime,
|
|
|
+ totalTime: formattedData.totalTime,
|
|
|
+ progressPercentage: formattedData.progressPercentage,
|
|
|
+ hasNext: formattedData.hasNext,
|
|
|
+ hasPrevious: formattedData.hasPrevious,
|
|
|
+ showProgress: formattedData.showProgress,
|
|
|
+ showCover: formattedData.showCover,
|
|
|
+ widgetSize: formattedData.widgetSize,
|
|
|
+ timestamp: formattedData.timestamp,
|
|
|
+ imgName: formattedData.imgName,
|
|
|
+ formImages: {} as Record<string, number>
|
|
|
+ };
|
|
|
+
|
|
|
+ // 设置图片文件描述符
|
|
|
+ if (dataWithImages.formImages) {
|
|
|
+ dataWithImages.formImages[data.imageFileInfo.fileName] = data.imageFileInfo.fd;
|
|
|
+ }
|
|
|
+
|
|
|
+ formData = formBindingData.createFormBindingData(dataWithImages);
|
|
|
+ hilog.info(0x0000, TAG, `📷 [${formId}] Created form data with image fd: ${data.imageFileInfo.fd} for ${data.imageFileInfo.fileName}`);
|
|
|
+ } else {
|
|
|
+ formData = formBindingData.createFormBindingData(formattedData);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新卡片
|
|
|
await formProvider.updateForm(formId, formData);
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `✅ [${formId}] Form updated successfully`);
|
|
|
+
|
|
|
|
|
|
// 保存增强状态信息
|
|
|
await this.saveEnhancedFormState(prefs, formId, widgetSizeStr, data);
|
|
|
@@ -313,22 +406,204 @@ export class EnhancedFormUpdateService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 预处理图片数据 - 转换本地文件URI为卡片可用格式
|
|
|
+ */
|
|
|
+ private async preprocessImageData(data: WidgetData): Promise<WidgetData> {
|
|
|
+ try {
|
|
|
+ // 修改点1: 显式声明processedData的类型为WidgetData
|
|
|
+ let processedData: WidgetData = data;
|
|
|
+ const coverImagePath = data.currentSong.coverImagePath;
|
|
|
+
|
|
|
+ if (!coverImagePath || coverImagePath.trim() === '') {
|
|
|
+ hilog.info(0x0000, TAG, '📷 No cover image path, skipping preprocessing');
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `📷 Processing cover image: ${coverImagePath}`);
|
|
|
+
|
|
|
+ // 处理本地文件URI
|
|
|
+ if (this.isLocalFileUri(coverImagePath)) {
|
|
|
+ hilog.info(0x0000, TAG, `📷 Detected local file URI: ${coverImagePath}`);
|
|
|
+
|
|
|
+ const processedImageInfo = await this.processLocalImageFile(coverImagePath);
|
|
|
+
|
|
|
+ if (processedImageInfo) {
|
|
|
+ // 创建新的数据对象,包含处理后的图片信息
|
|
|
+ processedData.currentSong.coverImagePath = processedImageInfo.memoryUri;
|
|
|
+ processedData.imageFileInfo = processedImageInfo as ImageFileInfo;
|
|
|
+ // const processedData: WidgetData = {
|
|
|
+ // ...data,
|
|
|
+ // currentSong: {
|
|
|
+ // ...data.currentSong,
|
|
|
+ // coverImagePath: processedImageInfo.memoryUri // 使用 memory:// 格式
|
|
|
+ // },
|
|
|
+ // // 添加图片文件信息用于后续处理
|
|
|
+ // imageFileInfo: processedImageInfo
|
|
|
+ // };
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `📷 Local image processed successfully: ${processedImageInfo.fileName} -> ${processedImageInfo.memoryUri}`);
|
|
|
+ return processedData;
|
|
|
+ } else {
|
|
|
+ hilog.warn(0x0000, TAG, `📷 Failed to process local image, using original data`);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 处理网络图片
|
|
|
+ else if (this.isNetworkUrl(coverImagePath)) {
|
|
|
+ hilog.info(0x0000, TAG, `📷 Detected network image: ${coverImagePath}`);
|
|
|
+ // 网络图片在 handleNetworkImage 中处理
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ // 其他情况
|
|
|
+ else {
|
|
|
+ hilog.info(0x0000, TAG, `📷 Using image path as-is: ${coverImagePath}`);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ hilog.error(0x0000, TAG, `❌ Error preprocessing image data: ${error}`);
|
|
|
+ return data; // 出错时返回原始数据
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理本地图片文件
|
|
|
+ */
|
|
|
+ private async processLocalImageFile(fileUri: string): Promise<ProcessedImageInfo | null> {
|
|
|
+ try {
|
|
|
+ hilog.info(0x0000, TAG, `📷 Processing local image file: ${fileUri}`);
|
|
|
+
|
|
|
+ // 转换 file:// URI 为实际文件路径
|
|
|
+ // file://com.xgplayer.ttmusic.hm/data/storage/el2/base/haps/entry/files/xxx.jpg
|
|
|
+ // 转换为 /data/storage/el2/base/haps/entry/files/xxx.jpg
|
|
|
+ let realPath = fileUri.replace('file://', '');
|
|
|
+
|
|
|
+ // 如果路径包含应用包名,需要移除它并构建正确的绝对路径
|
|
|
+ if (realPath.startsWith('com.xgplayer.ttmusic.hm/')) {
|
|
|
+ // 移除包名前缀,获取相对路径
|
|
|
+ const relativePath = realPath.replace('com.xgplayer.ttmusic.hm/', '');
|
|
|
+ // 使用应用上下文获取正确的文件路径
|
|
|
+ realPath = `${this.appContext!.filesDir}/${relativePath.split('/').pop()}`;
|
|
|
+ hilog.info(0x0000, TAG, `📷 Converted path with package name: ${fileUri} -> ${realPath}`);
|
|
|
+ } else if (!realPath.startsWith('/')) {
|
|
|
+ // 如果不是绝对路径,添加根路径
|
|
|
+ realPath = `/${realPath}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `📷 Final resolved path: ${realPath}`);
|
|
|
+
|
|
|
+ // 检查源文件是否存在
|
|
|
+ if (!fileIo.accessSync(realPath)) {
|
|
|
+ hilog.error(0x0000, TAG, `📷 Source image file does not exist: ${realPath}`);
|
|
|
+
|
|
|
+ // 尝试备用路径查找
|
|
|
+ const fileName = realPath.split('/').pop();
|
|
|
+ const alternativePaths = [
|
|
|
+ `${this.appContext!.filesDir}/${fileName}`,
|
|
|
+ `${this.appContext!.cacheDir}/${fileName}`,
|
|
|
+ `${this.appContext!.tempDir}/${fileName}`
|
|
|
+ ];
|
|
|
+
|
|
|
+ let foundPath: string | null = null;
|
|
|
+ for (const altPath of alternativePaths) {
|
|
|
+ if (fileIo.accessSync(altPath)) {
|
|
|
+ foundPath = altPath;
|
|
|
+ hilog.info(0x0000, TAG, `📷 Found file at alternative path: ${altPath}`);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!foundPath) {
|
|
|
+ hilog.error(0x0000, TAG, `📷 File not found in any location: ${fileName}`);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ realPath = foundPath;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成目标文件名(确保每次都不同,符合官方文档要求)
|
|
|
+ const fileExtension = this.getFileExtension(realPath) || 'jpg';
|
|
|
+ const fileName = `widget_local_${Date.now()}_${Math.random().toString(36).substr(2, 9)}.${fileExtension}`;
|
|
|
+
|
|
|
+ // 使用 FormExtensionAbility 的 tempDir(官方文档要求)
|
|
|
+ const formTempDir = this.appContext!.getApplicationContext().tempDir;
|
|
|
+ const tempFilePath = `${formTempDir}/${fileName}`;
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `📷 Using tempDir: ${formTempDir}`);
|
|
|
+
|
|
|
+ // 复制文件到临时目录
|
|
|
+ fileIo.copyFileSync(realPath, tempFilePath);
|
|
|
+
|
|
|
+ // 获取文件描述符
|
|
|
+ const file = fileIo.openSync(tempFilePath, fileIo.OpenMode.READ_ONLY);
|
|
|
+ const fd = file.fd;
|
|
|
+
|
|
|
+ const memoryUri = `memory://${fileName}`;
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `📷 Local image copied successfully: ${realPath} -> ${tempFilePath}, fd: ${fd}`);
|
|
|
+
|
|
|
+ const result: ProcessedImageInfo = {
|
|
|
+ fileName,
|
|
|
+ memoryUri,
|
|
|
+ fd
|
|
|
+ };
|
|
|
+
|
|
|
+ return result;
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ hilog.error(0x0000, TAG, `❌ Failed to process local image: ${error}`);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查是否为本地文件URI
|
|
|
+ */
|
|
|
+ private isLocalFileUri(url: string): boolean {
|
|
|
+ return url.startsWith('file://');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取文件扩展名
|
|
|
+ */
|
|
|
+ private getFileExtension(filePath: string): string | null {
|
|
|
+ const lastDotIndex = filePath.lastIndexOf('.');
|
|
|
+ if (lastDotIndex === -1 || lastDotIndex === filePath.length - 1) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return filePath.substring(lastDotIndex + 1).toLowerCase();
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 处理网络图片(缓存 + 下载)
|
|
|
*/
|
|
|
private async handleNetworkImage(adaptedData: FormattedWidgetData): Promise<void> {
|
|
|
- if (!adaptedData.coverImage || !this.isNetworkUrl(adaptedData.coverImage)) {
|
|
|
+ if (!adaptedData.coverImage) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
+ // 如果已经是 memory:// 格式(本地图片已处理),直接返回
|
|
|
+ if (adaptedData.coverImage.startsWith('memory://')) {
|
|
|
+ hilog.info(0x0000, TAG, `📷 Image already processed as memory URI: ${adaptedData.coverImage}`);
|
|
|
+ const fileName = adaptedData.coverImage.replace('memory://', '');
|
|
|
+ adaptedData.imgName = fileName;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理网络图片
|
|
|
+ if (!this.isNetworkUrl(adaptedData.coverImage)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
const imageUrl = adaptedData.coverImage;
|
|
|
- hilog.info(0x0000, TAG, `🖼️ Processing network image: ${imageUrl}`);
|
|
|
+
|
|
|
|
|
|
// 检查缓存
|
|
|
const cachedItem = this.imageCache.get(imageUrl);
|
|
|
if (cachedItem && cachedItem.expiry > Date.now()) {
|
|
|
- hilog.info(0x0000, TAG, `📸 Using cached image: ${cachedItem.fileName}`);
|
|
|
+
|
|
|
adaptedData.coverImage = `memory://${cachedItem.fileName}`;
|
|
|
adaptedData.imgName = cachedItem.fileName;
|
|
|
return;
|
|
|
@@ -339,12 +614,12 @@ export class EnhancedFormUpdateService {
|
|
|
if (fileName) {
|
|
|
adaptedData.coverImage = `memory://${fileName}`;
|
|
|
adaptedData.imgName = fileName;
|
|
|
- hilog.info(0x0000, TAG, `📸 Network image processed: ${fileName}`);
|
|
|
+
|
|
|
} else {
|
|
|
// 下载失败,清除图片
|
|
|
adaptedData.coverImage = '';
|
|
|
adaptedData.imgName = '';
|
|
|
- hilog.warn(0x0000, TAG, `⚠️ Failed to download image, using default`);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
@@ -360,7 +635,7 @@ export class EnhancedFormUpdateService {
|
|
|
private async downloadAndCacheImage(imageUrl: string): Promise<string | null> {
|
|
|
// 检查是否正在下载
|
|
|
if (this.downloadingImages.has(imageUrl)) {
|
|
|
- hilog.info(0x0000, TAG, `⏳ Image already downloading: ${imageUrl}`);
|
|
|
+
|
|
|
return await this.downloadingImages.get(imageUrl)!;
|
|
|
}
|
|
|
|
|
|
@@ -381,7 +656,7 @@ export class EnhancedFormUpdateService {
|
|
|
*/
|
|
|
private async performImageDownload(imageUrl: string): Promise<string | null> {
|
|
|
try {
|
|
|
- hilog.info(0x0000, TAG, `📥 Downloading image: ${imageUrl}`);
|
|
|
+
|
|
|
|
|
|
const httpRequest = http.createHttp();
|
|
|
const response = await httpRequest.request(imageUrl, {
|
|
|
@@ -401,7 +676,8 @@ export class EnhancedFormUpdateService {
|
|
|
const filePath = `${this.appContext!.cacheDir}/${fileName}`;
|
|
|
const file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY);
|
|
|
|
|
|
- const buffer = response.result as ArrayBuffer;
|
|
|
+ // 修改点2: 显式声明buffer的类型为ArrayBuffer
|
|
|
+ const buffer: ArrayBuffer = response.result as ArrayBuffer;
|
|
|
fileIo.writeSync(file.fd, new Uint8Array(buffer));
|
|
|
fileIo.closeSync(file);
|
|
|
|
|
|
@@ -416,7 +692,7 @@ export class EnhancedFormUpdateService {
|
|
|
this.imageCache.set(imageUrl, cacheItem);
|
|
|
this.cleanupImageCache();
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `✅ Image downloaded and cached: ${fileName} (${buffer.byteLength} bytes)`);
|
|
|
+
|
|
|
|
|
|
httpRequest.destroy();
|
|
|
return fileName;
|
|
|
@@ -451,9 +727,9 @@ export class EnhancedFormUpdateService {
|
|
|
fileIo.unlinkSync(filePath);
|
|
|
}
|
|
|
this.imageCache.delete(url);
|
|
|
- hilog.info(0x0000, TAG, `🗑️ Cleaned up cached image: ${item.fileName}`);
|
|
|
+
|
|
|
} catch (error) {
|
|
|
- hilog.warn(0x0000, TAG, `⚠️ Failed to cleanup image: ${error}`);
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -475,13 +751,67 @@ export class EnhancedFormUpdateService {
|
|
|
// 删除超过24小时的文件
|
|
|
if (Date.now() - stat.mtime > this.imageCacheExpiry) {
|
|
|
fileIo.unlinkSync(filePath);
|
|
|
- hilog.info(0x0000, TAG, `🗑️ Cleaned up expired cache file: ${file}`);
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- hilog.warn(0x0000, TAG, `⚠️ Failed to cleanup cache directory: ${error}`);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 预先验证卡片ID的有效性
|
|
|
+ */
|
|
|
+ private async preValidateFormIds(formIds: string[], prefs: preferences.Preferences): Promise<string[]> {
|
|
|
+ const validFormIds: string[] = [];
|
|
|
+ const invalidFormIds: string[] = [];
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `🔍 Pre-validating ${formIds.length} form IDs...`);
|
|
|
+
|
|
|
+ for (const formId of formIds) {
|
|
|
+ try {
|
|
|
+ // 尝试使用一个简单的测试数据来验证卡片ID
|
|
|
+ const testData = formBindingData.createFormBindingData({
|
|
|
+ test: 'validation'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 尝试更新卡片,如果失败说明卡片ID无效
|
|
|
+ await formProvider.updateForm(formId, testData);
|
|
|
+ validFormIds.push(formId);
|
|
|
+ hilog.debug(0x0000, TAG, `✅ [${formId}] Valid form ID`);
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ const errorStr :string= error.toString();
|
|
|
+ if (errorStr.includes('form not exist') ||
|
|
|
+ errorStr.includes('16501001') ||
|
|
|
+ errorStr.includes('The ID of the form to be operated does not exist')) {
|
|
|
+ hilog.warn(0x0000, TAG, `❌ [${formId}] Invalid form ID detected during validation`);
|
|
|
+ invalidFormIds.push(formId);
|
|
|
+ } else {
|
|
|
+ // 其他错误,可能是临时性的,保留该ID
|
|
|
+ hilog.warn(0x0000, TAG, `⚠️ [${formId}] Validation error (keeping): ${error}`);
|
|
|
+ validFormIds.push(formId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理无效的卡片ID
|
|
|
+ if (invalidFormIds.length > 0) {
|
|
|
+ hilog.info(0x0000, TAG, `🗑️ Cleaning up ${invalidFormIds.length} invalid form IDs`);
|
|
|
+ for (const invalidFormId of invalidFormIds) {
|
|
|
+ try {
|
|
|
+ await this.preferencesUtil.removeFormId(prefs, invalidFormId);
|
|
|
+ this.globalWidgetManager.unregisterWidget(invalidFormId);
|
|
|
+ hilog.info(0x0000, TAG, `🗑️ [${invalidFormId}] Cleaned up invalid form ID`);
|
|
|
+ } catch (cleanupError) {
|
|
|
+ hilog.error(0x0000, TAG, `❌ [${invalidFormId}] Failed to cleanup: ${cleanupError}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ hilog.info(0x0000, TAG, `🔍 Validation complete: ${validFormIds.length} valid, ${invalidFormIds.length} invalid`);
|
|
|
+ return validFormIds;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -491,23 +821,23 @@ export class EnhancedFormUpdateService {
|
|
|
const activeWidgets = this.globalWidgetManager.getActiveWidgets();
|
|
|
const activeFormIds = Array.from(activeWidgets.keys());
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `🔍 Validating widgets - Persistent: [${formIds.join(', ')}], Active: [${activeFormIds.join(', ')}]`);
|
|
|
+
|
|
|
|
|
|
// 检查持久化但不活跃的卡片
|
|
|
const persistentOnlyIds = formIds.filter(id => !activeWidgets.has(id));
|
|
|
if (persistentOnlyIds.length > 0) {
|
|
|
- hilog.warn(0x0000, TAG, `⚠️ Found ${persistentOnlyIds.length} persistent but inactive widgets: [${persistentOnlyIds.join(', ')}]`);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// 检查活跃但未持久化的卡片
|
|
|
const activeOnlyIds = activeFormIds.filter(id => !formIds.includes(id));
|
|
|
if (activeOnlyIds.length > 0) {
|
|
|
- hilog.warn(0x0000, TAG, `⚠️ Found ${activeOnlyIds.length} active but not persistent widgets: [${activeOnlyIds.join(', ')}]`);
|
|
|
+
|
|
|
|
|
|
// 将活跃的卡片添加到持久化存储
|
|
|
for (const formId of activeOnlyIds) {
|
|
|
await this.preferencesUtil.addFormId(prefs, formId);
|
|
|
- hilog.info(0x0000, TAG, `➕ Added missing form ID to persistence: ${formId}`);
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -529,9 +859,9 @@ export class EnhancedFormUpdateService {
|
|
|
};
|
|
|
|
|
|
await this.preferencesUtil.saveFormState(prefs, formId, stateData);
|
|
|
- hilog.info(0x0000, TAG, `💾 [${formId}] Enhanced form state saved (update #${updateCount})`);
|
|
|
+
|
|
|
} catch (error) {
|
|
|
- hilog.warn(0x0000, TAG, `⚠️ [${formId}] Failed to save enhanced form state: ${error}`);
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -552,7 +882,7 @@ export class EnhancedFormUpdateService {
|
|
|
if (updateResult.success) {
|
|
|
successCount++;
|
|
|
totalUpdateTime += updateResult.updateTime;
|
|
|
- hilog.info(0x0000, TAG, `✅ Form ${index + 1}/${formIds.length} (${formId}) updated successfully in ${updateResult.updateTime}ms (${updateResult.retryCount} retries)`);
|
|
|
+
|
|
|
} else {
|
|
|
failedCount++;
|
|
|
hilog.error(0x0000, TAG, `❌ Form ${index + 1}/${formIds.length} (${formId}) failed: ${updateResult.error?.message}`);
|
|
|
@@ -587,28 +917,28 @@ export class EnhancedFormUpdateService {
|
|
|
const errorStr = error.toString();
|
|
|
const formId = formIds[index];
|
|
|
|
|
|
- hilog.warn(0x0000, TAG, `🔍 Analyzing error for form ${formId}: ${errorStr}`);
|
|
|
+
|
|
|
|
|
|
if (errorStr.includes('form not exist') ||
|
|
|
errorStr.includes('16501001') ||
|
|
|
errorStr.includes('FormProvider') ||
|
|
|
errorStr.includes('invalid form')) {
|
|
|
- hilog.warn(0x0000, TAG, `🗑️ Form ${formId} appears to be invalid, marking for cleanup`);
|
|
|
+
|
|
|
invalidFormIds.push(formId);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
if (invalidFormIds.length > 0) {
|
|
|
- hilog.info(0x0000, TAG, `🧹 Cleaning up ${invalidFormIds.length} invalid forms: [${invalidFormIds.join(', ')}]`);
|
|
|
+
|
|
|
|
|
|
for (const invalidFormId of invalidFormIds) {
|
|
|
await this.preferencesUtil.removeFormId(prefs, invalidFormId);
|
|
|
this.globalWidgetManager.unregisterWidget(invalidFormId);
|
|
|
- hilog.info(0x0000, TAG, `🗑️ Removed invalid form ID: ${invalidFormId}`);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- hilog.info(0x0000, TAG, `✅ Invalid forms cleaned up successfully`);
|
|
|
+
|
|
|
}
|
|
|
} catch (error) {
|
|
|
hilog.error(0x0000, TAG, `❌ Failed to cleanup invalid forms: ${error}`);
|
|
|
@@ -639,7 +969,7 @@ export class EnhancedFormUpdateService {
|
|
|
failedUpdates: 0,
|
|
|
averageUpdateTime: 0
|
|
|
};
|
|
|
- hilog.info(0x0000, TAG, '📊 Update statistics reset');
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|