1.問題描述:

卡片裏的Iamge無法顯示網絡圖片。

解決方案:

通過FormExtensionAbility在元服務卡片上加載網絡圖片有以下兩種方案:

  • 方案一:先下載網絡圖片到本地,參考元服務卡片上加載本地圖片示例代碼在EntryFormAbility的onAddForm生命週期回調中實現本地文件的刷新。刷新後,在卡片頁面通過backgroundImage屬性展示EntryFormAbility傳遞過來的卡片內容。
  • 方案二:申請ohos.permission.INTERNET權限,創建HTTP請求,下載網絡圖片數據並保存到應用的臨時文件中,在EntryFormAbility的onFormEvent生命週期回調中實現網絡文件的刷新。刷新後,在卡片頁面通過backgroundImage屬性展示EntryFormAbility傳遞過來的卡片內容。使用這種方案在元服務卡片上加載網絡圖片示例代碼詳見元服務卡片上加載網絡圖片指南。

2.問題描述:

如何在主應用中獲取卡片的添加/移除?

解決方案:

一、卡片添加/移除的場景以及相關卡片生命週期 由於目前卡片添加/移除至桌面目前沒有直接完成的回調響應,可以通過onAddForm和onRemoveForm結合記錄保存到桌面的卡片,onAddForm/onRemoveForm添加至桌面的生命週期觸發流程如下:

  1. 長按應用圖標->服務卡片->打開卡片列表,觸發onAddForm (卡片列表中有幾張卡片生命週期就會回調onAddForm幾次)。例如:打開下面的卡片列表,卡片列表中有3張卡片,可以看到日誌中OnAddForm回調了3次。
  2. 服務卡片列表取消->觸發onRemoveForm(卡片列表中有幾張卡片生命週期就會回調觸發onRemoveForm幾次)。 例如:點擊x號取消了服務卡片列表,則會出發OnRemoveForm回調3次。
  3. 服務卡片列表選擇->某一張卡片添加到桌面(卡片生命週期onAddForm選中的卡片,onRemoveForm其餘卡片)。例如:添加一張卡片至桌面,則會OnAddForm選中的的卡片,OnRemove另外兩張卡片。
  4. 移除某一張卡片(卡片生命週期onRemoveForm移除的卡片)。例如:在桌面移除一張卡片,會OnRemove當前移除的卡片。 綜上流程,卡片整個添加至桌面的流程中,中間狀態生命週期onAddForm/onRemoveForm會回調多次,但是最終卡片新增還是移除是確定的。

二、實現卡片添加/移除管理以及通知主應用的實現 本方案使用首選項通過在服務卡片中onAddForm/onRemoveForm回調函數中,對formId進行持久化緩存,並在主應用中進行跨進程讀取。以下是實現步驟:

  1. 實現一個公共的單例首選項類以供服務卡片/主應用共同使用,需要注意的是,這裏首選項對於跨進程的場景下,需要使用同一個context上下文對象,後面在調用處均使用了this.context.getApplicationContext()保持統一。
import { preferences } from '@kit.ArkData';

export class PreferencesHelper {
private static instance: PreferencesHelper | null = null
private preferences: preferences.Preferences | null = null
private ctx: Context | null = null
private PREFERENCE_NAME:string = "preferences"

private constructor() {}

public static getInstance(ctx: Context) {
  if (PreferencesHelper.instance === null) {
    PreferencesHelper.instance = new PreferencesHelper()
  }
   PreferencesHelper.instance.init(ctx)
  return PreferencesHelper.instance
}

private init(ctx: Context) {
  this.ctx = ctx
  this.preferences = preferences.getPreferencesSync(ctx, { name: this.PREFERENCE_NAME})
}

public get(key: string, defaultValue: Array<string>) {
  if (!this.preferences) {
    return
  }
  console.log("get ", defaultValue);
  let options: preferences.Options = { name: this.PREFERENCE_NAME };
   preferences.removePreferencesFromCacheSync(this.ctx, options);
  return this.preferences.getSync(key, defaultValue)
}

public put(key: string, defaultValue: preferences.ValueType) {
  if (!this.preferences) {
    return
  }
  console.log("put ", defaultValue);
  this.preferences.putSync(key, defaultValue)
   this.preferences.flushSync()
}

public clear() {
  PreferencesHelper.instance = null
  this.preferences = null
}
}
  1. 當長按應用圖標拉起應用卡片列表時以及在卡片列表中選擇一張服務卡片時,會觸發onAddForm,此時將卡片id保存下來:(注意:formlist需要做去重)
// 服務卡片FormExtensionAbility.ets
      onAddForm(want: Want) {
         console.log('onAddForm')
        let ctx = this.context.getApplicationContext()
        let formList: Array<string> =
           PreferencesHelper.getInstance(ctx).get('formList', []) as Array<string>
        if (want.parameters) {
          let formId = (want.parameters['ohos.extra.param.key.form_identity']) as string
          // 為了保證formId的唯一性,需要對formList去重
          !formList.includes(formId) && formList.push(formId)
           PreferencesHelper.getInstance(ctx).put('formList', formList)
        }
        const formData = '';
        return formBindingData.createFormBindingData(formData);
      }
  1. 服務卡片列表取消時或者在桌面移除卡片時,會觸發onRemoveForm,此時將記錄裏對應的數據刪除,剩餘的即是添加到桌面的卡片:(注意:formlist需要做去重)
// 服務卡片FormExtensionAbility.ets
        onRemoveForm(formId: string) {
          let ctx = this.context.getApplicationContext()
          let formList: Array<string> = PreferencesHelper.getInstance(ctx).get('formList', []) as Array<string>
          // 為了保證formId的唯一性,需要對formList去重
          formList = formList.filter(item => item !== formId)
           PreferencesHelper.getInstance(ctx).put('formList', formList)
        }

4.然後,在主應用中對formId進行查詢:(注意:主應用需要和卡片使用同一個context)

// EntryAbility.ets
        build() {
          RelativeContainer() {
            Text(this.message)
              .id('HelloWorld')
          }
          .height('100%')
          .width('100%')
          .onClick(()=>{
            let formList: Array<string> =
               PreferencesHelper.getInstance(this.context.getApplicationContext()).get('formList', []) as Array<string>
             console.log("formList size %d", formList.length);
            for (let index = 0; index < formList.length; index++) {
              const element = formList[index];
               console.log("formId %d", element);
            }
          })
        }

3.問題描述:

卡片列表如何展示網絡圖片?

解決方案:

  1. 卡片裏面沒有直接聯網的權限,加載網絡圖片需要先將網絡圖片下載到本地,下載網絡圖片需要使用到網絡能力,需要申請ohos.permission.INTERNET權限。
let filesDir = context.getApplicationContext().filesDir
  let filePath = filesDir + 'xxx.png'
  request.downloadFile(context, {
    url: 'xxx', // 此處為圖片下載地址
    filePath,
  }).then((downloadTask: request.DownloadTask) => {
    downloadTask.on('complete', () => {
      console.log('download complete')
    })
  }).catch((err: BusinessError) => {
    console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
  });
  1. EntryFormAbility中的onFormEvent生命週期回調中實現網絡文件的刷新。
// 卡片需要顯示圖片場景,formData中formImages必填且不可改名,key值與thumb(結構和名稱可自定義)的值需保持一致,值為key對應的fd

  class News {
    thumb?: string = '';
    title: string = '';
  }

  class FormData {
    list: News[] = []
    formImages?: Record<string, number> = {};
  }

  onFormEvent(formId: string) {
    // 下載網絡圖片到本地,通過formImages
    let imgPath = await download(ctx)
    let file = fs.openSync(imgPath)
    let imageMap: Record<string, number> = {}
    imageMap[imgPath] = file.fd
    let res: FormData = {
      list: [
        {
          title: 'new',
          thumb: imgPath, // 需要與formImages的key值一致
        }
      ],
      formImages: imageMap
    }
    await formProvider.updateForm(formId, formBindingData.createFormBindingData(res))
    fs.closeSync(file)
  }
  1. 在卡片中通過memory:// + fileName的格式展示。
Image('memory://' + item?.thumb)