如何判断卡片是否添加到桌面
=============

#### 问题现象

如何判断应用的卡片是否已被添加至桌面。

#### 背景知识

*   [Form Kit（卡片开发服务）](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/formkit-overview)提供了一种在桌面、锁屏等系统应用上嵌入显示应用信息的开发框架和API，可以将应用内用户关注的重要信息或常用操作抽取到服务卡片（简称“卡片”）上，通过将卡片添加到桌面、锁屏等系统应用上，以达到信息展示、服务直达的便捷体验效果。
*   卡片扩展模块[FormExtensionAbility](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formextensionability)提供了卡片的创建、销毁、刷新等生命周期回调函数。
*   从API 20起，[formProvider](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formprovider)提供[getPublishedRunningFormInfos](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formprovider#formprovidergetpublishedrunningforminfos20)和[getPublishedRunningFormInfoById](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formprovider#formprovidergetpublishedrunningforminfobyid20)接口，可以获取应用已加桌的卡片的信息。

#### 解决方案

*   应用获取当前已加桌的卡片。
    
    从API 20起，使用[getPublishedRunningFormInfos](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formprovider#formprovidergetpublishedrunningforminfos20)获取当前应用已加桌的所有卡片的信息，若无卡片加桌，则报错误码[16500100](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/errorcode-form#section16500100-获取卡片配置信息失败)；使用[getPublishedRunningFormInfoById](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formprovider#formprovidergetpublishedrunningforminfobyid20)获取当前应用已加桌的指定ID卡片的信息，若指定ID的卡片不存在或未加桌，则报错误码[16500100](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/errorcode-form#section16500100-获取卡片配置信息失败)。
    
    import { formInfo, formProvider } from '@kit.FormKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    @Entry
    @Component
    struct Index {
      @State widgetCount: number = 0;
      @State isGettingOne: boolean = false;
      @State isGettingTwo: boolean = false;
      @State widgetInfoGotten: string = '';
      @State formIdTmp: string = '';
      @State formId: string = '';
      @StorageProp('FormArr') widgetCountByLifeCycle: string\[\] = \[\];
    
      build() {
        Column({ space: 16 }) {
          Button('获取加桌卡片数量')
            .type(ButtonType.Capsule)
            .onClick(() => {
              this.isGettingOne = true;
            _  // 获取本应用全部已加桌卡片的信息_
              try {
                formProvider.getPublishedRunningFormInfos().then((data: formInfo.RunningFormInfo\[\]) => {
                _  // 当前应用有卡片已加桌，卡片信息获取成功_
                  console.info(\`promise success.\`);
                  this.formIdTmp = data\[0\].formId;
                  this.widgetCount = data.length;
                }).catch((error: BusinessError) => {
                _  // 当前应用无卡片加桌，进入报错_
                  this.widgetCount = 0;
                  console.error(\`promise error, code: ${error.code}, message: ${error.message}\`);
                });
              } catch (error) {
                console.error(\`catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}\`);
              }
            });
    
          if (this.isGettingOne) {
            Text(\`本应用已加桌卡片数量：${this.widgetCount}\`)
              .fontSize('18fp')
              .fontWeight(FontWeight.Bold)
              .height(40);
          } else {
            Row()
              .height(40);
          }
    
          Button('获取指定ID的加桌卡片信息')
            .type(ButtonType.Capsule)
            .onClick(() => {
              this.isGettingTwo = true;
           _   // 获取本应用已加桌的指定ID卡片的信息_
              try {
                this.formId = this.formIdTmp;
                formProvider.getPublishedRunningFormInfoById(this.formId).then((data: formInfo.RunningFormInfo) => {
              _    // 指定卡片已加桌，卡片信息获取成功_
                  console.info(\`promise success, form id: ${data.formId}\`);
                  this.widgetInfoGotten = 'Got';
                }).catch((error: BusinessError) => {
             _     // 指定卡片不存在或未加桌，进入报错_
                  console.error(\`promise error, code: ${error.code}, message: ${error.message}\`);
                  this.widgetInfoGotten = 'No got';
                });
              } catch (error) {
                console.error(\`catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}\`);
                this.widgetInfoGotten = 'error';
              }
            });
    
          if (this.isGettingTwo) {
            Text(\`卡片id：${this.formId}，信息获取：${this.widgetInfoGotten}\`)
              .fontSize('18fp')
              .fontWeight(FontWeight.Bold)
              .height(40);
          } else {
            Row()
              .height(40);
          }
        }
        .height('100%')
        .width('100%')
        .justifyContent(FlexAlign.Center);
      }
    }
    
*   加桌时确认卡片是否成功加桌。
    *   从API 20起，卡片扩展模块[FormExtensionAbility](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formextensionability)提供[onFormLocationChanged](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-formextensionability#formextensionabilityonformlocationchanged20)生命周期回调函数，当卡片从卡片管理器中添加至桌面时，会触发onFormLocationChanged回调，[FormLocation](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-form-forminfo#formlocation20)结果返回0，表示当前卡片位置为桌面。
    *   在API 20前，卡片在加桌时会触发onAddForm生命周期回调函数，可以通过want.parameters的ohos.extra.param.key.form\_location字段获取卡片位置，当字段值为0时，表示卡片位置为桌面。
        
        import { formBindingData, FormExtensionAbility, formInfo } from '@kit.FormKit';
        import { Want } from '@kit.AbilityKit';
        
        export default class EntryFormAbility extends FormExtensionAbility {
          onAddForm(want: Want) {
          _  // Called to return a FormBindingData object._
            const formData = '';
            if (want.parameters) {
              console.info(\`====> Form location: ${want.parameters\['ohos.extra.param.key.form\_location'\]}\`);
            }
            return formBindingData.createFormBindingData(formData);
          }
        
          onRemoveForm() {
         _   // Called to notify the form provider that a specified form has been destroyed._
          }
        
          onCastToNormalForm() {
           _ // Called when the form provider is notified that a temporary form is successfully_
            _// converted to a normal form._
          }
        
          onUpdateForm() {
           _ // Called to notify the form provider to update a specified form._
          }
        
          onFormEvent() {
          _  // Called when a specified message event defined by the form provider is triggered._
          }
        
          onAcquireFormState() {
           _ // Called to return a {@link FormState} object._
            return formInfo.FormState.READY;
          }
        
          onFormLocationChanged(formId: string, newFormLocation: formInfo.FormLocation): void {
            console.info(\`formId: ${formId}, now location: ${newFormLocation}\`);
          }
        };
        

#### 总结

*   从API 20起，可以通过接口getPublishedRunningFormInfos或getPublishedRunningFormInfoById获取已加桌卡片的信息，或在生命周期的onFormLocationChanged回调函数中确认卡片是否添加到桌面。
*   在API 20前，可以通过onAddForm回调函数中的卡片位置字段，确认卡片是否添加到桌面。