chendeben 1 год назад
Родитель
Сommit
fd152714a0

+ 188 - 58
entry/src/main/ets/common/service/UnifiedPlayerService.ets

@@ -37,6 +37,8 @@ import { util } from '@kit.ArkTS';
 import json from '@ohos.util.json';
 import MediaTable from '../util/MediaTable';
 import { Utility } from '../util/Utility';
+import { FormRdbHelper } from '../../database/FormRdbHelper';
+import { FormInfo } from '../../viewmodel/FormInfo';
 
 /**
  * 服务就绪状态详情接口
@@ -495,6 +497,9 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       // 异步初始化耗时组件,避免阻塞
       this.initializeHeavyComponentsAsync(context);
 
+      // 清理无效的Form ID
+      this.cleanupInvalidFormIds();
+
       LogUtils.getInstance().LOGI('UnifiedPlayerService: Core initialization completed');
     } catch (error) {
       LogUtils.getInstance().LOGI(`UnifiedPlayerService initialization error: ${error}`);
@@ -502,6 +507,44 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     }
   }
 
+  /**
+   * 为卡片进程设置context
+   * 卡片进程是独立的,需要单独设置context
+   */
+  setFormContext(context: common.UIAbilityContext | common.FormExtensionContext): void {
+    try {
+      this.context = context as common.UIAbilityContext;
+      // 同时设置到AppStorage,确保卡片进程中其他地方能访问
+      AppStorage.setOrCreate('context', context);
+      LogUtils.getInstance().LOGI('UnifiedPlayerService: Form context set successfully');
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to set form context: ${error}`);
+    }
+  }
+
+  /**
+   * 获取当前context
+   */
+  getContext(): common.UIAbilityContext | null {
+    // 优先返回实例的context
+    if (this.context) {
+      return this.context;
+    }
+    
+    // 尝试从AppStorage获取
+    try {
+      const appStorageContext = AppStorage.get('context') as common.UIAbilityContext;
+      if (appStorageContext) {
+        this.context = appStorageContext;
+        return appStorageContext;
+      }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to get context from AppStorage: ${error}`);
+    }
+    
+    return null;
+  }
+
   /**
    * 异步初始化耗时组件
    */
@@ -1059,12 +1102,10 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
   getFav(): Array<VideoItem> {
     if (this.favList.length > 0) {
-      console.log("Heanup UnifiedPlayerService favList cached:" + json.stringify(this.favList));
       return this.favList;
     }
     // 如果缓存为空,异步更新但返回空数组,避免阻塞
     this.getTable().queryByisFav(1, async (result: VideoItem[]) => {
-      console.log("Heanup UnifiedPlayerService favList:" + json.stringify(result));
       this.favList = result;
       // 更新收藏列表后,重新更新AVSession状态以反映正确的收藏状态
       if (result.length > 0) {
@@ -1613,7 +1654,6 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
       // 播放事件监听
       avSession.on('play', () => {
-        LogUtils.getInstance().LOGI('UnifiedPlayerService: AVSession play command received');
         this.startPlayOrResumePlay().catch((error: Error) => {
           LogUtils.getInstance().LOGI(`AVSession play command failed: ${error}`);
         });
@@ -2195,7 +2235,6 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       // 保存播放进度
       this.savePlaybackPosition();
 
-      LogUtils.getInstance().LOGI('UnifiedPlayerService: Current state saved');
     } catch (error) {
       LogUtils.getInstance().LOGI(`UnifiedPlayerService saveCurrentState error: ${error}`);
     }
@@ -2807,68 +2846,65 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     // 定义变量在方法开始处,确保在整个方法中都可以访问
     try {
       const now = Date.now();
-      // 防重复调用:如果正在更新或距离上次更新时间太近,则跳过(除非强制更新)
-      if (!forceUpdate && (this.isUpdatingForms || (now - this.lastUpdateTime) < this.UPDATE_THROTTLE_MS)) {
-        LogUtils.getInstance()
-          .LOGI(`UnifiedPlayerService updateAllForms: Skipping duplicate call (last update: ${now -
-          this.lastUpdateTime}ms ago)`);
-        return;
-      }
       this.isUpdatingForms = true;
       this.lastUpdateTime = now;
-      // 从持久化存储获取所有formId
+      // 从数据库获取所有Form信息
       const context = AppStorage.get('context') as common.UIAbilityContext;
       if (!context) {
         LogUtils.getInstance().LOGI('UnifiedPlayerService updateAllForms: No context available');
         return;
       }
 
-      const preferencesUtil: PreferencesUtil = PreferencesUtil.getInstance();
-      const prefs = await preferencesUtil.getPreferences(context);
-      const formIds: string[] = await preferencesUtil.getFormIds(prefs);
+      // 从数据库读取所有Form信息
+      let formInfoList: FormInfo[] = [];
+      try {
+        formInfoList = await FormRdbHelper.getInstance(context).queryAllForms();
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Found ${formInfoList.length} forms in database`);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to query forms from database: ${error}`);
+        return;
+      }
 
-      if (formIds.length === 0) {
-        LogUtils.getInstance().LOGI('UnifiedPlayerService updateAllForms: No form IDs found');
+      if (formInfoList.length === 0) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService updateAllForms: No forms found in database');
         return;
       }
 
 
       // 记录更新统计
-      let successCount = 0;
-      let failedCount = 0;
       const invalidFormIds: string[] = [];
-      let flatWidgetData = this.getWidgetFormData();
-      if (flatWidgetData) {
-        // 逐个更新所有卡片
-        for (const formId of formIds) {
+      let flatWidgetData = await this.getWidgetFormData();
+
+        // 逐个更新所有卡片,根据卡片类型进行个性化处理
+        for (const formInfo of formInfoList) {
           try {
             const formBindingDataInstance = formBindingData.createFormBindingData(flatWidgetData);
-            await formProvider.updateForm(formId, formBindingDataInstance);
-            successCount++;
+            await formProvider.updateForm(formInfo.formId, formBindingDataInstance);
+
+            LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Successfully updated form ${formInfo.formId} (${formInfo.formName})`);
           } catch (error) {
-            failedCount++;
             const errorStr: string = error?.toString() || '';
-            invalidFormIds.push(formId);
+            invalidFormIds.push(formInfo.formId);
             LogUtils.getInstance()
-              .LOGI(`UnifiedPlayerService updateAllForms: Form ${formId} - ${errorStr}}`);
-
+              .LOGI(`UnifiedPlayerService updateAllForms: Form ${formInfo.formId} (${formInfo.formName}) - ${errorStr}}`);
           }
+        }
 
-          // 自动清理无效的Form ID
-          if (invalidFormIds.length > 0) {
-            try {
-              await preferencesUtil.removeFormIds(prefs, invalidFormIds);
-              LogUtils.getInstance()
-                .LOGI(`UnifiedPlayerService updateAllForms: Removed ${invalidFormIds.length} invalid form IDs: ${invalidFormIds.join(', ')}`);
-            } catch (error) {
-              LogUtils.getInstance()
-                .LOGI(`UnifiedPlayerService updateAllForms: Failed to clean invalid form IDs: ${error}`);
+        // 自动清理无效的Form ID
+        if (invalidFormIds.length > 0) {
+          try {
+            for (const invalidFormId of invalidFormIds) {
+              await FormRdbHelper.getInstance(context).deleteForm(invalidFormId);
             }
+            LogUtils.getInstance()
+              .LOGI(`UnifiedPlayerService updateAllForms: Removed ${invalidFormIds.length} invalid form IDs from database: ${invalidFormIds.join(', ')}`);
+          } catch (error) {
+            LogUtils.getInstance()
+              .LOGI(`UnifiedPlayerService updateAllForms: Failed to clean invalid form IDs from database: ${error}`);
           }
         }
-      }
 
-    } catch (error) {
+      } catch (error) {
       LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms error: ${error}`);
     } finally {
       // 重置更新标志
@@ -2884,9 +2920,14 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     this.lastUpdateTime = now;
     const formData: VideoItem = this.getCurrentSong() as VideoItem; // VideoItem
     const songState: PlayerState = this.getCurrentState(); // PlayerState
-    // 从持久化存储获取所有formId
-    const context = AppStorage.get('context') as common.UIAbilityContext;
-
+    
+    // 从持久化存储获取所有formId - 使用新的getContext方法
+    let context = this.getContext();
+    
+    // 如果还是没有context,尝试从AppStorage获取
+    if (!context) {
+      context = AppStorage.get('context') as common.UIAbilityContext;
+    }
 
     // 构建卡片数据,包含VideoItem和PlayerState信息
     const widgetPlayerState: WidgetPlayerState = {
@@ -2911,7 +2952,8 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       progressPercentage: this.calculateProgressPercentage(songState.currentPosition || 0, songState.duration || 0)
     };
 
-    if (!context || !formData) {
+    if (!formData) {
+      console.log('UnifiedPlayerService getWidgetFormData: No formData available - formData:'+json.stringify(formData))
       const defaultData: widgeData = {
         id: '',
         name: '未知歌曲',
@@ -2942,7 +2984,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       }
       return defaultData;
     }
-
+    console.log('UnifiedPlayerService getWidgetFormData -  context: '+json.stringify(context)+" - formData:"+json.stringify(formData))
     // 处理封面图片
     let imgName: string = '';
 
@@ -3080,15 +3122,6 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
     return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
   }
 
-  /**
-   * 歌曲变化时更新卡片
-   */
-  private async updateWidgetsForSongChange(song: VideoItem, forceUpdate: boolean = false): Promise<void> {
-
-    this.updateAllForms();
-
-  }
-
 
   /**
    * 状态变化时更新卡片
@@ -3271,10 +3304,6 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
 
       // 记录上次更新时间
       this.lastAvSessionUpdate = now;
-
-      LogUtils.getInstance()
-        .LOGI(`UnifiedPlayerService: AVSession play state updated successfully` + JSON.stringify(playbackState));
-
     } catch (error) {
       LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to update AVSession play state: ${error}`);
     }
@@ -3568,4 +3597,105 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
       LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to clean expired cache: ${error}`);
     }
   }
+
+  /**
+   * 清理无效的Form ID
+   * 应用启动时调用,验证所有保存的Form ID是否仍然有效
+   */
+  private async cleanupInvalidFormIds(): Promise<void> {
+    try {
+      if (!this.context) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService: No context for cleanup invalid form IDs');
+        return;
+      }
+      // 从数据库读取所有Form信息
+      let formInfoList: FormInfo[] = [];
+      try {
+        formInfoList = await FormRdbHelper.getInstance(this.context).queryAllForms();
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService cleanupInvalidFormIds: Found ${formInfoList.length} forms in database`);
+      } catch (error) {
+        LogUtils.getInstance().LOGI(`UnifiedPlayerService cleanupInvalidFormIds: Failed to query forms from database: ${error}`);
+        return;
+      }
+
+      if (formInfoList.length === 0) {
+        LogUtils.getInstance().LOGI('UnifiedPlayerService cleanupInvalidFormIds: No forms found in database');
+        return;
+      }
+
+
+      // 记录更新统计
+      const invalidFormIds: string[] = [];
+      let flatWidgetData = await this.getWidgetFormData();
+
+      // 逐个更新所有卡片,根据卡片类型进行个性化处理
+      for (const formInfo of formInfoList) {
+        try {
+          const formBindingDataInstance = formBindingData.createFormBindingData(flatWidgetData);
+          await formProvider.updateForm(formInfo.formId, formBindingDataInstance);
+
+          LogUtils.getInstance().LOGI(`UnifiedPlayerService cleanupInvalidFormIds: Successfully updated form ${formInfo.formId} (${formInfo.formName})`);
+        } catch (error) {
+          const errorStr: string = error?.toString() || '';
+          invalidFormIds.push(formInfo.formId);
+          LogUtils.getInstance()
+            .LOGI(`UnifiedPlayerService cleanupInvalidFormIds: Form ${formInfo.formId} (${formInfo.formName}) - ${errorStr}}`);
+        }
+      }
+
+      // 自动清理无效的Form ID
+      if (invalidFormIds.length > 0) {
+        try {
+          for (const invalidFormId of invalidFormIds) {
+            await FormRdbHelper.getInstance(this.context).deleteForm(invalidFormId);
+          }
+          LogUtils.getInstance()
+            .LOGI(`UnifiedPlayerService cleanupInvalidFormIds: Removed ${invalidFormIds.length} invalid form IDs from database: ${invalidFormIds.join(', ')}`);
+        } catch (error) {
+          LogUtils.getInstance()
+            .LOGI(`UnifiedPlayerService cleanupInvalidFormIds: Failed to clean invalid form IDs from database: ${error}`);
+        }
+      }
+
+
+
+      // const preferencesUtil = PreferencesUtil.getInstance();
+      // const prefs = await preferencesUtil.getPreferences(this.context);
+      // const formIds = await preferencesUtil.getFormIds(prefs);
+      //
+      // if (formIds.length === 0) {
+      //   LogUtils.getInstance().LOGI('UnifiedPlayerService: No form IDs to cleanup');
+      //   return;
+      // }
+      //
+      // const invalidFormIds: string[] = [];
+      //
+      // // 逐个验证Form ID的有效性
+      // for (const formId of formIds) {
+      //   try {
+      //     // 尝试更新卡片来验证其有效性
+      //     const flatWidgetData = await this.getWidgetFormData();
+      //     if (flatWidgetData) {
+      //       const formBindingDataInstance = formBindingData.createFormBindingData(flatWidgetData);
+      //       await formProvider.updateForm(formId, formBindingDataInstance);
+      //     }
+      //   } catch (error) {
+      //     // 如果更新失败,说明这个Form ID无效
+      //     invalidFormIds.push(formId);
+      //     LogUtils.getInstance().LOGI(`UnifiedPlayerService: Invalid form ID detected: ${formId}, error: ${error}`);
+      //   }
+      // }
+      //
+      // // 移除无效的Form ID
+      // if (invalidFormIds.length > 0) {
+      //
+      //
+      //   LogUtils.getInstance().LOGI(`UnifiedPlayerService: Cleaned up ${invalidFormIds.length} invalid form IDs: ${invalidFormIds.join(', ')}`);
+      // } else {
+      //   LogUtils.getInstance().LOGI(`UnifiedPlayerService: All ${formIds.length} form IDs are valid`);
+      // }
+    } catch (error) {
+      LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to cleanup invalid form IDs: ${error}`);
+    }
+  }
 }

+ 1 - 1
entry/src/main/ets/common/util/Utility.ets

@@ -390,7 +390,7 @@ export class Utility {
   }
 
   //判断是否是媒体文件  音乐和视频都可以
-  static isMeidaByExtension(filename:string) {
+  static isMediaByExtension(filename:string) {
     const extensions = CommonConstants.MEDIA_FORMAT
     const lastIndex = filename.lastIndexOf('.');
     if (lastIndex!== -1) {

+ 263 - 0
entry/src/main/ets/database/FormRdbHelper.ets

@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import relationalStore from '@ohos.data.relationalStore';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { FormInfo } from '../viewmodel/FormInfo';
+
+const TAG = 'FormRdbHelper';
+
+/**
+ * Form数据库操作助手类
+ */
+export class FormRdbHelper {
+  private static instance: FormRdbHelper;
+  private rdbStore: relationalStore.RdbStore | null = null;
+  private context: Context | null = null;
+  
+  /**
+   * 数据库配置
+   */
+  private static readonly STORE_CONFIG: relationalStore.StoreConfig = {
+    name: 'FormDatabase.db',
+    securityLevel: relationalStore.SecurityLevel.S1,
+    encrypt: false
+  };
+
+  /**
+   * 表名
+   */
+  private static readonly FORM_TABLE = 'form_info';
+
+  /**
+   * 创建表的SQL语句
+   */
+  private static readonly CREATE_TABLE_SQL = `CREATE TABLE IF NOT EXISTS ${FormRdbHelper.FORM_TABLE} (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    form_id TEXT NOT NULL UNIQUE,
+    form_name TEXT NOT NULL,
+    form_dimension TEXT NOT NULL,
+    create_time TEXT NOT NULL,
+    update_time TEXT NOT NULL
+  )`;
+
+  private constructor() {}
+
+  /**
+   * 获取单例实例
+   */
+  static getInstance(context?: Context): FormRdbHelper {
+    if (!FormRdbHelper.instance) {
+      FormRdbHelper.instance = new FormRdbHelper();
+    }
+    if (context && !FormRdbHelper.instance.context) {
+      FormRdbHelper.instance.context = context;
+    }
+    return FormRdbHelper.instance;
+  }
+
+  /**
+   * 初始化数据库
+   */
+  private async initDatabase(): Promise<void> {
+    if (this.rdbStore) {
+      return;
+    }
+
+    if (!this.context) {
+      throw new Error('Context is not available');
+    }
+
+    try {
+      this.rdbStore = await relationalStore.getRdbStore(this.context, FormRdbHelper.STORE_CONFIG);
+      await this.rdbStore.executeSql(FormRdbHelper.CREATE_TABLE_SQL);
+      hilog.info(0x0000, TAG, 'Database initialized successfully');
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to initialize database: ${businessError.message}`);
+      throw new Error(businessError.message);
+    }
+  }
+
+  /**
+   * 获取数据库实例
+   */
+  private async getRdbStore(): Promise<relationalStore.RdbStore> {
+    if (!this.rdbStore) {
+      await this.initDatabase();
+    }
+    return this.rdbStore!;
+  }
+
+  /**
+   * 插入Form信息
+   */
+  async insertForm(formInfo: FormInfo): Promise<void> {
+    try {
+      const store = await this.getRdbStore();
+      let exist=await this.queryFormById(formInfo.formId);
+      if (exist) {
+        return ;
+      }else {
+        const valueBucket: relationalStore.ValuesBucket = {
+          'form_id': formInfo.formId,
+          'form_name': formInfo.formName,
+          'form_dimension': formInfo.formDimension,
+          'create_time': formInfo.createTime,
+          'update_time': formInfo.updateTime,
+        };
+        console.log('插入数据:'+JSON.stringify(valueBucket))
+        await store.insert(FormRdbHelper.FORM_TABLE, valueBucket);
+        hilog.info(0x0000, TAG, `Form inserted successfully: ${formInfo.formId}`);
+      }
+
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to insert form: ${businessError.message}`);
+      throw new Error(businessError.message);    }
+  }
+
+  /**
+   * 根据formId查询Form信息
+   */
+  async queryFormById(formId: string): Promise<FormInfo| undefined> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(FormRdbHelper.FORM_TABLE);
+      predicates.equalTo('form_id', formId);
+
+      const resultSet = await store.query(predicates);
+      if (resultSet.rowCount === 0) {
+        resultSet.close();
+        return undefined;
+      }
+
+      resultSet.goToFirstRow();
+      const formInfo = new FormInfo();
+      formInfo.formId = resultSet.getString(resultSet.getColumnIndex('form_id'));
+      formInfo.formName = resultSet.getString(resultSet.getColumnIndex('form_name'));
+      formInfo.formDimension = resultSet.getString(resultSet.getColumnIndex('form_dimension'));
+      formInfo.createTime = resultSet.getString(resultSet.getColumnIndex('create_time'));
+      formInfo.updateTime = resultSet.getString(resultSet.getColumnIndex('update_time'));
+      resultSet.close();
+      hilog.info(0x0000, TAG, `Form queried successfully: ${formId}`);
+      return formInfo;
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to query form: ${businessError.message}`);
+      return undefined;
+    }
+  }
+
+  /**
+   * 查询所有Form信息
+   */
+  async queryAllForms(): Promise<FormInfo[]> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(FormRdbHelper.FORM_TABLE);
+      const resultSet = await store.query(predicates);
+
+      const forms: FormInfo[] = [];
+      if (resultSet.rowCount > 0) {
+        resultSet.goToFirstRow();
+        do {
+          const formInfo = new FormInfo();
+          formInfo.formId = resultSet.getString(resultSet.getColumnIndex('form_id'));
+          formInfo.formName = resultSet.getString(resultSet.getColumnIndex('form_name'));
+          formInfo.formDimension = resultSet.getString(resultSet.getColumnIndex('form_dimension'));
+          formInfo.createTime = resultSet.getString(resultSet.getColumnIndex('create_time'));
+          formInfo.updateTime = resultSet.getString(resultSet.getColumnIndex('update_time'));
+          forms.push(formInfo);
+        } while (resultSet.goToNextRow());
+      }
+
+      resultSet.close();
+      hilog.info(0x0000, TAG, `Queried ${forms.length} forms`);
+      return forms;
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to query all forms: ${businessError.message}`);
+      throw new Error(businessError.message);    }
+  }
+
+  /**
+   * 更新Form信息
+   */
+  async updateForm(formInfo: FormInfo): Promise<void> {
+    try {
+      const store = await this.getRdbStore();
+      const valueBucket: relationalStore.ValuesBucket = {
+        'form_name': formInfo.formName,
+        'form_dimension': formInfo.formDimension,
+        'update_time': new Date().toISOString()
+      };
+
+      const predicates = new relationalStore.RdbPredicates(FormRdbHelper.FORM_TABLE);
+      predicates.equalTo('form_id', formInfo.formId);
+
+      await store.update(valueBucket, predicates);
+      hilog.info(0x0000, TAG, `Form updated successfully: ${formInfo.formId}`);
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to update form: ${businessError.message}`);
+      throw new Error(businessError.message);    }
+  }
+
+  /**
+   * 删除Form信息
+   */
+  async deleteForm(formId: string): Promise<void> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(FormRdbHelper.FORM_TABLE);
+      predicates.equalTo('form_id', formId);
+
+      await store.delete(predicates);
+      hilog.info(0x0000, TAG, `Form deleted successfully: ${formId}`);
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to delete form: ${businessError.message}`);
+      throw new Error(businessError.message);    }
+  }
+
+  /**
+   * 清空所有Form信息
+   */
+  async clearAllForms(): Promise<void> {
+    try {
+      const store = await this.getRdbStore();
+      const predicates = new relationalStore.RdbPredicates(FormRdbHelper.FORM_TABLE);
+      await store.delete(predicates);
+      hilog.info(0x0000, TAG, 'All forms cleared successfully');
+    } catch (error) {
+      const businessError = error as BusinessError;
+      hilog.error(0x0000, TAG, `Failed to clear all forms: ${businessError.message}`);
+      throw new Error(businessError.message);
+    }
+  }
+
+  /**
+   * 关闭数据库
+   */
+  async close(): Promise<void> {
+    if (this.rdbStore) {
+      await this.rdbStore.close();
+      this.rdbStore = null;
+      hilog.info(0x0000, TAG, 'Database closed');
+    }
+  }
+}

+ 34 - 2
entry/src/main/ets/entryability/EntryAbility.ets

@@ -12,7 +12,7 @@ import hilog from '@ohos.hilog';
 import window from '@ohos.window';
 import { AbilityConstant, Want } from '@kit.AbilityKit';
 import { BusinessError, emitter } from '@kit.BasicServicesKit';
-import { AppUtil, ArrayUtil, GlobalContext, LogUtil, StrUtil } from '@pura/harmony-utils';
+import { AppUtil, GlobalContext, LogUtil, StrUtil } from '@pura/harmony-utils';
 import { rpc } from '@kit.IPCKit';
 import { Utility } from '../common/util/Utility';
 import { WXApi, WXEventHandler } from '../common/util/WXApiWrap';
@@ -21,6 +21,7 @@ import { systemShare } from '@kit.ShareKit';
 import { CustomCrashHandler } from '../common/utils/CustomCrashHandler';
 import { smartMobilityCommon } from '@kit.CarKit';
 import { display } from '@kit.ArkUI';
+import {PreferencesUtil} from '../common/utils/PreferencesUtil'
 
 
 /**
@@ -201,7 +202,7 @@ export default class EntryAbility extends UIAbility {
                     message: uri
                 }
             };
-            if(Utility.isMeidaByExtension(uri)){
+            if(Utility.isMediaByExtension(uri)){
                 emitter.emit({ eventId: 2 }, eventData); // 发送音频打开广播事件
             }else{
                 emitter.emit({ eventId: 1 }, eventData); // 发送视频打开广播事件
@@ -246,6 +247,13 @@ export default class EntryAbility extends UIAbility {
             hilog.error(0x0000, 'Heanup2', `Failed to release UnifiedPlayerService: ${error}`);
         }
 
+        // 清理所有Form ID(应用卸载时)
+        try {
+            this.clearAllFormIds();
+        } catch (error) {
+            hilog.error(0x0000, 'Heanup2', `Failed to clear form IDs: ${error}`);
+        }
+
         // 注销卡片call事件监听器
         this.unregisterWidgetCallListeners();
 
@@ -837,4 +845,28 @@ export default class EntryAbility extends UIAbility {
         const secs = Math.floor(seconds % 60);
         return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
     }
+
+    /**
+     * 清理所有Form ID
+     * 应用销毁时调用,确保清理所有持久化的Form ID
+     */
+    private async clearAllFormIds(): Promise<void> {
+        try {
+            const preferencesUtil = PreferencesUtil.getInstance();
+            const prefs = await preferencesUtil.getPreferences(this.context);
+            
+            // 获取所有Form ID
+            const formIds = await preferencesUtil.getFormIds(prefs);
+            
+            if (formIds.length > 0) {
+                // 清理所有Form ID
+                await preferencesUtil.removeFormIds(prefs, formIds);
+                hilog.info(0x0000, 'Heanup2', `Cleared ${formIds.length} form IDs on app destroy: ${formIds.join(', ')}`);
+            } else {
+                hilog.info(0x0000, 'Heanup2', 'No form IDs to clear on app destroy');
+            }
+        } catch (error) {
+            hilog.error(0x0000, 'Heanup2', `Failed to clear form IDs: ${error}`);
+        }
+    }
 }

+ 68 - 83
entry/src/main/ets/entryformability/EntryFormAbility.ets

@@ -1,48 +1,12 @@
-import { formBindingData, FormExtensionAbility, formProvider } from '@kit.FormKit';
+import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
 import { Want } from '@kit.AbilityKit';
 import { hilog } from '@kit.PerformanceAnalysisKit';
-
 import { PreferencesUtil } from '../common/utils/PreferencesUtil';
-import { UnifiedPlayerService, WidgetFormData } from '../common/service/UnifiedPlayerService';
-import { VideoItem } from '../viewmodel/VideoItem';
-
-const TAG = 'Heanup EntryFormAbility';
-
-/**
- * 卡片数据接口 - 用于EntryFormAbility的数据构建
- */
-interface FormWidgetData {
-  // VideoItem数据平铺
-  id: string;
-  name: string;
-  artist: string;
-  album: string;
-  pixelMapPath: string;
-  duration: number;
-  filePath: string;
-  imgName: string;
-  imageColorHex: string;
-
-  // PlayerState数据平铺
-  isPlaying: boolean;
-  isPaused: boolean;
-  isLoading: boolean;
-  currentPosition?: number;
-  hasNext: boolean;
-  hasPrevious: boolean;
-  playMode?: number;
-
-  // 播放列表信息平铺
-  currentIndex?: number;
-  totalCount?: number;
-
-  // 时间信息平铺
-  currentTimeText?: string;
-  totalTimeText?: string;
-  progressPercentage?: number;
-}
-
+import { UnifiedPlayerService } from '../common/service/UnifiedPlayerService';
+import { FormRdbHelper } from '../database/FormRdbHelper';
+import { FormInfo } from '../viewmodel/FormInfo';
 
+const TAG = 'EntryFormAbility';
 
 
 /**
@@ -59,36 +23,55 @@ export default class EntryFormAbility extends FormExtensionAbility {
    * 卡片创建时调用
    */
   onAddForm(want: Want): formBindingData.FormBindingData {
+    hilog.info(0x0000, TAG, 'onAddForm');
+    
     // 检查参数有效性
     if (!want || !want.parameters) {
       hilog.error(0x0000, TAG, 'FormAbility onAddForm want or want.parameters is undefined');
       return formBindingData.createFormBindingData({});
     }
 
+    // 确保为卡片进程设置context
+    if (!this.unifiedPlayerService.getContext()) {
+      console.info(`[EntryFormAbility] Setting context for form process`);
+      try {
+        // 为卡片进程设置context
+        this.unifiedPlayerService.setFormContext(this.context);
+      } catch (error) {
+        console.error(`[EntryFormAbility] Failed to set form context: ${error}`);
+      }
+    }
+
     // 初始化服务
     try {
       this.initializeServices();
     } catch (error) {
-      hilog.error(0x0000, TAG, `Heanup EntryFormAbility failed to initialize services: ${error}`);
+      hilog.error(0x0000, TAG, `EntryFormAbility failed to initialize services: ${error}`);
     }
 
     const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string;
-    
+    const formName = want.parameters?.['ohos.extra.param.key.form_name'] as string;
+    const formDimension = want.parameters?.['ohos.extra.param.key.form_dimension'] as string;
+
     // 增加详细日志
     console.info(`[EntryFormAbility] onAddForm called with formId: ${formId}`);
-    console.info(`[EntryFormAbility] want.parameters:`, JSON.stringify(want.parameters));
-
-    // 持久化保存 Form ID(异步执行,不阻塞返回)
-    this.saveFormIdToPersistence(formId).then(() => {
-      console.info('[Heanup] saveFormIdToPersistence success:'+ formId);
-      // Form ID保存后,延迟一段时间再触发数据更新,确保Form已准备好
-      setTimeout(() => {
-        console.info(`[EntryFormAbility] Triggering delayed update for form ${formId}`);
-        this.unifiedPlayerService.updateAllForms();
-      }, 500); // 延迟500ms
-    }).catch((error: Error) => {
-      console.error('[Heanup] saveFormIdToPersistence failed:'+ error.message);
-    });
+    console.info(`[EntryFormAbility] formName: ${formName}, dimension: ${formDimension}`);
+
+    // 创建FormInfo对象并保存到数据库
+    if (formId && formName && formDimension) {
+      let formInfo = new FormInfo();
+      formInfo.formId = formId;
+      formInfo.formDimension = formDimension;
+      formInfo.formName = formName;
+
+      hilog.info(0x0000, TAG, `onAddForm formInfo: ${JSON.stringify(formInfo)}`);
+      
+      // 保存到数据库
+      FormRdbHelper.getInstance(this.context).insertForm(formInfo).catch((error: Error) => {
+        hilog.error(0x0000, TAG, `Failed to insert form to database: ${error.message}`);
+      });
+
+    }
 
     // 返回初始数据作为临时显示
     const adaptedData = this.unifiedPlayerService.getWidgetFormData();
@@ -97,26 +80,24 @@ export default class EntryFormAbility extends FormExtensionAbility {
     return formBindingData.createFormBindingData(adaptedData);
   }
 
+
   /**
    * 卡片更新时调用
    */
   onUpdateForm(formId: string): void {
-    console.info(`[EntryFormAbility] onUpdateForm called for ${formId}`);
-    // 使用统一的更新机制
-    this.unifiedPlayerService.updateAllForms();
+    hilog.info(0x0000, TAG, `onUpdateForm formId:${formId}`);
   }
 
   /**
    * 卡片删除时调用
    */
   onRemoveForm(formId: string): void {
+    hilog.info(0x0000, TAG, 'onRemoveForm');
     console.info(`[EntryFormAbility] onRemoveForm called for ${formId}`);
     
-    // 从持久化存储中移除 Form ID(异步执行)
-    this.removeFormIdFromPersistence(formId).then(() => {
-      console.info(`[EntryFormAbility] Form ID ${formId} removed from persistence`);
-    }).catch((error: Error) => {
-      console.error(`[EntryFormAbility] Failed to remove Form ID ${formId}: ${error.message}`);
+    // 从数据库中删除Form信息
+    FormRdbHelper.getInstance(this.context).deleteForm(formId).catch((error: Error) => {
+      hilog.error(0x0000, TAG, `Failed to delete form from database: ${error.message}`);
     });
   }
 
@@ -128,7 +109,7 @@ export default class EntryFormAbility extends FormExtensionAbility {
 
     const formIds = Object.keys(newStatus);
     let hasVisibleForm = false;
-    
+
     for (let i = 0; i < formIds.length; i++) {
       const formId = formIds[i];
       const isVisible = newStatus[formId] === 1;
@@ -137,7 +118,7 @@ export default class EntryFormAbility extends FormExtensionAbility {
         hasVisibleForm = true;
       }
     }
-    
+
     // 如果有卡片变为可见,触发一次统一更新
     if (hasVisibleForm) {
       this.unifiedPlayerService.updateAllForms();
@@ -155,13 +136,17 @@ export default class EntryFormAbility extends FormExtensionAbility {
   }
 
   /**
-   * 处理卡片尺寸变化(系统调用)
-   * @param newStatus 新的尺寸状态
+   * 卡片状态变化时调用
+   */
+  onCastToNormalForm(formId: string) {
+    hilog.info(0x0000, TAG, 'onCastToNormalForm');
+  }
+
+  /**
+   * 处理卡片事件
    */
-  onAcquireFormState(want: Want): number {
+  onFormEvent(formId: string, message: string) {
 
-    // 返回卡片状态 - 使用数字常量代替枚举
-    return 1; // READY状态
   }
 
   /**
@@ -181,16 +166,16 @@ export default class EntryFormAbility extends FormExtensionAbility {
     try {
       console.info(`[EntryFormAbility] Starting to save Form ID: ${formId}`);
       console.info(`[EntryFormAbility] Context available: ${!!this.context}`);
-      
+
       const preferencesUtil = PreferencesUtil.getInstance();
       const prefs = await preferencesUtil.getPreferences(this.context);
-      
+
       // 保存前查看当前的Form ID列表
       const currentFormIds = await preferencesUtil.getFormIds(prefs);
       console.info(`[EntryFormAbility] Current Form IDs before save: ${currentFormIds.join(', ')}`);
-      
+
       await preferencesUtil.addFormId(prefs, formId);
-      
+
       // 保存后再次查看Form ID列表
       const updatedFormIds = await preferencesUtil.getFormIds(prefs);
       console.info(`[EntryFormAbility] Form IDs after save: ${updatedFormIds.join(', ')}`);
@@ -206,20 +191,20 @@ export default class EntryFormAbility extends FormExtensionAbility {
    */
   private async removeFormIdFromPersistence(formId: string): Promise<void> {
     try {
-      console.info(`[EntryFormAbility] Starting to remove Form ID: ${formId}`);
-      
+      console.info(`[EntryFormAbility] 开始移除 Form ID: ${formId}`);
+
       const preferencesUtil = PreferencesUtil.getInstance();
       const prefs = await preferencesUtil.getPreferences(this.context);
-      
+
       // 移除前查看当前的Form ID列表
-      const currentFormIds = await preferencesUtil.getFormIds(prefs);
-      console.info(`[EntryFormAbility] Current Form IDs before remove: ${currentFormIds.join(', ')}`);
-      
+      // const currentFormIds = await preferencesUtil.getFormIds(prefs);
+      // console.info(`[EntryFormAbility] Current Form IDs before remove: ${currentFormIds.join(', ')}`);
+
       await preferencesUtil.removeFormId(prefs, formId);
-      
+
       // 移除后再次查看Form ID列表
       const updatedFormIds = await preferencesUtil.getFormIds(prefs);
-      console.info(`[EntryFormAbility] Form IDs after remove: ${updatedFormIds.join(', ')}`);
+      console.info(`[EntryFormAbility]移除后的 Form IDs: ${updatedFormIds.join(', ')}`);
 
     } catch (error) {
       hilog.error(0x0000, TAG, `❌ Failed to remove Form ID: ${error}`);

+ 1 - 1
entry/src/main/ets/pages/ScanFilePage.ets

@@ -539,7 +539,7 @@ async function  scanDirectoryTask(context: Context, dirPath: string, lockPath: s
       } else {
         if (fPath.endsWith('.lrc')  || fPath.endsWith('.srt'))  return;
 
-        if (Utility.isMeidaByExtension(fPath))  {
+        if (Utility.isMediaByExtension(fPath))  {
           const mediaItem = await Utility.uriGetMusicAssetsFromFile(
             context, fPath, CommonConstants.TYPE_LOCAL, true
           );

+ 4 - 4
entry/src/main/ets/view/LocalMusic.ets

@@ -1252,10 +1252,10 @@ export struct LocalMusic {
         // Utility.doSortListAscending(directories)
 
       } else {
-        if (this.currentPath === this.lockPath&&Utility.isMeidaByExtension(path)) {
+        if (this.currentPath === this.lockPath&&Utility.isMediaByExtension(path)) {
           let item: VideoItem =
             await Utility.uriGetMusicAssetsFromFile(this.context, path, CommonConstants.TYPE_LOCAL, false);
-          if (!path.endsWith('.lrc') && Utility.isMeidaByExtension(path) && !path.endsWith('.srt')) {
+          if (!path.endsWith('.lrc') && Utility.isMediaByExtension(path) && !path.endsWith('.srt')) {
             files.push(item);
             // files.sort((a, b) => a.cTime.localeCompare(b.cTime));
             // this.doSortListAscending(files)
@@ -1356,7 +1356,7 @@ export struct LocalMusic {
 
         Logger.info('onecold scanDirectory filePath = ' + fPath)
         // Process media files
-        if (!fPath.endsWith('.lrc') && Utility.isMeidaByExtension(fPath) && !fPath.endsWith('.srt')) {
+        if (!fPath.endsWith('.lrc') && Utility.isMediaByExtension(fPath) && !fPath.endsWith('.srt')) {
           let mediaItem: VideoItem =
             await Utility.uriGetMusicAssetsFromFile(this.context, fPath, CommonConstants.TYPE_LOCAL, true);
           mediaItems.push(mediaItem);
@@ -1887,7 +1887,7 @@ export struct LocalMusic {
 
 
         if (this.currentPath !== this.lockPath) { //判断不是私密音乐,才入库
-          if (!filePath.endsWith('.lrc') && Utility.isMeidaByExtension(filePath) && !filePath.endsWith('.srt')) {
+          if (!filePath.endsWith('.lrc') && Utility.isMediaByExtension(filePath) && !filePath.endsWith('.srt')) {
             let mediaItem: VideoItem =
               await Utility.uriGetMusicAssetsFromFile(this.context, filePath, CommonConstants.TYPE_LOCAL, true);
             this.table.insert(mediaItem, (id: number) => {

+ 49 - 0
entry/src/main/ets/viewmodel/FormInfo.ets

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Form信息数据模型
+ */
+export class FormInfo {
+  /**
+   * 卡片ID
+   */
+  formId: string = '';
+  
+  /**
+   * 卡片名称
+   */
+  formName: string = '';
+  
+  /**
+   * 卡片尺寸
+   */
+  formDimension: string = '';
+  
+  /**
+   * 创建时间
+   */
+  createTime: string = '';
+  
+  /**
+   * 更新时间
+   */
+  updateTime: string = '';
+
+  constructor() {
+    this.createTime = new Date().toISOString();
+    this.updateTime = new Date().toISOString();
+  }
+}

+ 1 - 1
entry/src/main/ets/workers/Worker.ets

@@ -74,7 +74,7 @@ async function scanDirectory(context: Context, curPath: string, lockPath: string
               mediaItems = mediaItems.concat(subItems);
             })());
           } else {
-            if(!fPath.endsWith('.lrc')&&Utility.isMeidaByExtension(fPath)&&!fPath.endsWith('.srt')){
+            if(!fPath.endsWith('.lrc')&&Utility.isMediaByExtension(fPath)&&!fPath.endsWith('.srt')){
               // 用 Promise 包装媒体处理逻辑
               pendingTasks.push((async  () => {
                 let mediaItem:VideoItem = await Utility.uriGetMusicAssetsFromFile(context, fPath,