一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

服務器資訊|IT/互聯網|云計算|區(qū)塊鏈|軟件資訊|操作系統(tǒng)|手機數碼|百科知識|免費資源|頭條新聞|

服務器之家 - 新聞資訊 - 操作系統(tǒng) - HarmonyOS開發(fā)實例—蜜蜂AI助手

HarmonyOS開發(fā)實例—蜜蜂AI助手

2024-01-04 17:06未知服務器之家 操作系統(tǒng)

想了解更多關于開源的內容,請訪問: 本站 鴻蒙開發(fā)者社區(qū) 一、前言 自華為宣布HarmonyOS NEXT全面啟動,近期新浪、B站、小紅書、支付寶等各領域頭部企業(yè)紛紛啟動鴻蒙原生應用開發(fā)。據媒體統(tǒng)計,如今Top20的應用里,已經有近一

HarmonyOS開發(fā)實例—蜜蜂AI助手

想了解更多關于開源的內容,請訪問:

本站 鴻蒙開發(fā)者社區(qū)

一、前言

自華為宣布HarmonyOS NEXT全面啟動,近期新浪、B站、小紅書、支付寶等各領域頭部企業(yè)紛紛啟動鴻蒙原生應用開發(fā)。據媒體統(tǒng)計,如今Top20的應用里,已經有近一半開始了鴻蒙原生應用開發(fā)。雖然目前HarmonyOS NEXT還未面向個人開發(fā)者開放,但我們可以體驗并使用最新的API9和開發(fā)工具,嘗試開發(fā)元服務,這個鴻蒙新的應用形態(tài)。體驗未來在HarmonyOS NEXT上實現的應用開發(fā)。但需要注意的是, 基于API9開發(fā)的應用或元服務是不可以適配HarmonyOS NEXT版本的,大家也可以期待一下明年推出的適配HarmonyOS NEXT新版本。

本文主要是基于蜜蜂AI元服務的開發(fā)案例:主要的功能有

元服務內部功能:

  • 提供兩個Tabs,首頁和我的。
  • 用戶只有登錄之后才可以去使用蜜蜂AI的功能。
  • 目前現有的知識庫包括知識百科小助手,節(jié)日小助手,文本翻譯小助手,產品名稱小助手,以及道歉信小助手等。
  • 用戶使用小助手之后,我們可以保存對話到列表內,下次快速的進行訪問。

元服務卡片:

  • 提供2-4的卡片,卡片界面展示每日妙語,點擊即可刷新。
  • 提供1-2的卡片,實現快速訪問首頁。
  • 提供2-2卡片,可以快速使用包括知識百科小助手,節(jié)日小助手,文本翻譯小助手,產品名稱小助手。
  • 提供4-4卡片,可以快速到達登陸頁面,訪問小助手等。

1、HarmonyOS

HarmonyOS是華為公司開發(fā)的操作系統(tǒng),它的設計理念是面向未來的全場景智慧體驗,可在各種設備上運行,包括手機、平板電腦、智能手表、智能音箱等。HarmonyOS采用分布式技術,可以將不同設備之間的計算資源連接起來,實現設備間的協(xié)同工作,提高系統(tǒng)的性能和穩(wěn)定性。此外,HarmonyOS還擁有高度自適應的界面、多屏協(xié)同等特性,使用戶能夠在不同設備上實現無縫的體驗。

2、元服務

在萬物互聯時代,人均持有設備量不斷攀升,設備和場景的多樣性,使應用開發(fā)變得更加復雜、應用入口更加多樣。在此背景下,應用提供方和用戶迫切需要一種新的服務提供方式,使應用開發(fā)更簡單、服務(如聽音樂、打車等)的獲取和使用更便捷。為此,HarmonyOS除支持傳統(tǒng)方式的需要安裝的應用(以下簡稱傳統(tǒng)應用)外,還支持更加方便快捷的免安裝的應用(即元服務)。

3、介紹AppGallery Connect(AGC)

AppGallery Connect(簡稱AGC)致力于為應用的創(chuàng)意、開發(fā)、分發(fā)、運營、經營各環(huán)節(jié)提供一站式服務,構建全場景智慧化的應用生態(tài)體驗。

4、蜜蜂AI元服務助手背景

目前AI正火,而我自己也想將鴻蒙和AI做一結合,于是有了蜜蜂這個作品。

元服務與傳統(tǒng)應用對比

項目

元服務

傳統(tǒng)應用

軟件包形態(tài)

App Pack(.app)

App Pack(.app)

分發(fā)平臺

由應用市場(AppGallery)管理和分發(fā)

由應用市場(AppGallery)管理和分發(fā)

安裝后有無桌面icon

無桌面icon,但可手動添加到桌面,顯示形式為服務卡片

有桌面icon

HAP免安裝要求

所有HAP(包括Entry HAP和Feature HAP)均需滿足免安裝要求

所有HAP(包括Entry HAP和Feature HAP)均為非免安裝的

新建元服務應用。

HarmonyOS開發(fā)實例—蜜蜂AI助手

開通:

HarmonyOS開發(fā)實例—蜜蜂AI助手

AI平臺https://fulitimes.com/登陸賬號17752170152

https://ai.fulitimes.com/model?modelId=

如何運行

HarmonyOS開發(fā)實例—蜜蜂AI助手

二、準備工作

1、HarmonyOS應用開發(fā)環(huán)境

工欲善其事,必先利其器,我們首先要做的就是搭建開發(fā)環(huán)境。

這里面我們分為三步走。

(1)環(huán)境安裝

首先在這邊安裝最新的IDE:

下載鏈接:http://m.ythuaji.com.cn/uploads/allimg/xexpbxd1ek5 style="text-align:center;">HarmonyOS開發(fā)實例—蜜蜂AI助手

(2)環(huán)境配置

下載完成之后,我們就開始配置開發(fā)環(huán)境。下載SDK及工具鏈,首次使用DevEco Studio,工具的配置向導會引導您下載SDK及工具鏈。配置向導默認下載 API Version 9的SDK及工具鏈,我們選擇默認就好。

下載nodejs和ohpm,記得最好HarmonyOS SDK路徑中不能包含中文字符。

HarmonyOS開發(fā)實例—蜜蜂AI助手

下載完成之后,我們下載HarmonyOS SDK。

在彈出的SDK下載信息頁面,單擊Next,并在彈出的License Agreement窗口,閱讀License協(xié)議,需同意License協(xié)議后,單擊Next。

目前最新的應該是3.2.13.5。

HarmonyOS開發(fā)實例—蜜蜂AI助手

確認設置項的信息,點擊Next開始安裝。

HarmonyOS開發(fā)實例—蜜蜂AI助手

等待Node.js、ohpm和SDK下載完成后,單擊Finish,界面會進入到DevEco Studio歡迎頁。

(3)創(chuàng)建HelloWord

在DevEco Studio的歡迎頁,選擇Create Project開始創(chuàng)建一個新工程。

HarmonyOS開發(fā)實例—蜜蜂AI助手

根據工程創(chuàng)建向導,在HarmonyOS頁簽,選擇“Empty Ability”模板,單擊Next。

HarmonyOS開發(fā)實例—蜜蜂AI助手

單擊Next,各個參數保持默認值即可,單擊Finish。

(4)運行Helloword

將搭載HarmonyOS手機與電腦連接。

HarmonyOS開發(fā)實例—蜜蜂AI助手

單擊File>Project Structure >Project > SigningConfigs界面勾選“支持HarmonyOS,以及Automatically generate signature”,等待自動簽名完成即可,單擊OK。如右所示:。

HarmonyOS開發(fā)實例—蜜蜂AI助手

在編輯窗口右上角的工具欄,單擊運行,等待編譯完成即可便運行在設備上。

這個時候真機就可以看到HelloWord。接下來我們就創(chuàng)建蜜蜂AI元服務。

2、創(chuàng)建蜜蜂AI元服務

這里我們的模版就不再選空模板了,而是直接選擇最后一個端云一體化模版

HarmonyOS開發(fā)實例—蜜蜂AI助手

然后其他的就按照上面的配置就可以。完成項目的配置。

這里有個區(qū)別就是我們需要關聯云資源。所以我們創(chuàng)建的應用包名要牢記,這個要在后面我們云端配置的時候使用。

為工程關聯云開發(fā)所需的資源,即在DevEco Studio中選擇您的華為開發(fā)者賬號加入的開發(fā)者團隊,將該團隊在AGC的同包名應用關聯到當前工程,具體操作如下:

  • 若尚未登錄DevEco Studio,單擊“Sign in”,拉起瀏覽器在彈出的賬號登錄頁面,使用已實名認證的華為開發(fā)者賬號完成登錄。

HarmonyOS開發(fā)實例—蜜蜂AI助手

單擊“Team”下拉框,選擇開發(fā)團隊。選中團隊后,系統(tǒng)根據工程包名自動查詢團隊下的同包名應用。若為首次創(chuàng)建且團隊下未創(chuàng)建同包名的應用,則提示需要在AGC平臺創(chuàng)建應用。

HarmonyOS開發(fā)實例—蜜蜂AI助手

單擊“AppGallery Connect”打開AGC應用創(chuàng)建向導,填寫應用信息,單擊“確認”按鈕創(chuàng)建應用。

完成以上操作后,DevEco Studio即可獲取到同包名應用對應的項目信息。

3、AGC配置

我們登陸云側,創(chuàng)建元服務。

HarmonyOS開發(fā)實例—蜜蜂AI助手

然后我們開通手機登陸和郵箱登錄服務。

HarmonyOS開發(fā)實例—蜜蜂AI助手

三、實現登錄

當前AGC認證服務為HarmonyOS應用/服務提供的登錄認證方式有手機、郵箱兩種方式。本工程使用“手機號碼+驗證碼”的方式作為應用的登錄入口。而且我們在前面已經開通。

在登陸這一塊,用戶首次登陸的時候,我們會首先利用首選項檢查他的登陸狀態(tài)。

首選項工具類

/**
 * 首選項操作類
 */
import { PreferenceDBUtil } from '../utils/PreferencesDBUtil';


const preDbService = new PreferenceDBUtil();
preDbService.getPreStorage();

export const getDBPre = async (key: string) => {
  const value = await preDbService.getPreVal(key);
  return value;
}

export const putDBPre = async (key: string, value: string) => {
  await preDbService.putPreData(key, value);
}

然后跳用調用AGConnectAuth.requestEmailVerifyCode申請驗證碼,在entry/src/main/ets/services/Auth.ts認證工具類中添加郵箱驗證碼獲取方法。

import { MainPage } from "@hw-agconnect/auth-component-ohos"
import router from '@ohos.router'
import { LogUtil } from '../common/utils/LogUtil';
import { Constants } from '../common/Constants';
import { putPre } from '../common/service/PreService';
import { UserInfo } from '../common/UserInfo';

@Entry
@Component
struct Index {
  @State icon: Resource = router.getParams()['icon'];
  @State isAgreement:boolean = router.getParams()['isAgreement'];
  @State agreementContent:string = router.getParams()['agreementContent'];
  @State onSuccess: Function = router.getParams()['onSuccess'];
  @State onError: Function = router.getParams()['onError'];

  build() {
    Column() {
      MainPage({
        icon: this.icon,
        agreement: {
          isAgreement: this.isAgreement,
          agreementContent: this.agreementContent,
        },
        onSuccess: async (user) => {
          LogUtil.info(`登錄用戶信息:${JSON.stringify(user)}`);
          const loginUser = user['user'];
          const userInfo: UserInfo = {
            uid: loginUser['uid'],
            email: loginUser['email'],
            phone: loginUser['phone'] === undefined ? "" : loginUser['phone'].split('-')[1],
            displayName: loginUser['displayName'] === undefined ? "" : loginUser['displayName'],
            photoUrl: loginUser['photoUrl'] === undefined ? "/common/imgs/ic_user.svg" : loginUser['photoUrl']
          }
          await putPre(Constants.LOGIN_USER_KEY, JSON.stringify(userInfo));
          router.back();
        },
        onError: (err) => {
          LogUtil.error(`登錄用戶信息:${JSON.stringify(err)}`);
        }
      })
    }
  }

  aboutToAppear() {
  }
}

未登錄彈窗

/**
 * 未登錄彈窗
 */
import common from '@ohos.app.ability.common';
import router from '@ohos.router';
import { GlobalConstant } from '../common/constants/GlobalConstant';
@CustomDialog
export struct LoginTipDialogView {
  loginTipCtrl: CustomDialogController;
  build() {
    Column({ space: GlobalConstant.SIZE_8 }) {
      Row({ space: GlobalConstant.SIZE_4 }) {
        Image($r('app.media.ic_tip'))
          .width(GlobalConstant.SIZE_32)
          .height(GlobalConstant.SIZE_32)
        Text('溫馨提示')
          .fontSize($r('app.float.font_size_24'))
          .fontColor($r('app.color.tip_color'))
          .fontWeight(FontWeight.Bolder)
      }
      .width(GlobalConstant.PAGE_FULL)
      .height(GlobalConstant.SIZE_64)
      .padding({ left: GlobalConstant.SIZE_16 })
      Text('您還未登錄,請登錄后體驗功能!')
        .height(GlobalConstant.SIZE_48)
        .fontSize(Color.Black)
        .fontSize($r('app.float.font_size_18'))
        .fontWeight(FontWeight.Normal)
      Row({ space: GlobalConstant.SIZE_8 }) {
        Button('退出', { type: ButtonType.Normal })
          .borderRadius(GlobalConstant.SIZE_4)
          .backgroundColor($r('app.color.embellishment_color'))
          .fontColor($r('app.color.text_color_9'))
          .onClick(() => {
            const ctx = getContext(this) as common.UIAbilityContext;
            ctx.terminateSelf();
          })
        Button('去登錄', { type: ButtonType.Normal })
          .borderRadius(GlobalConstant.SIZE_4)
          .backgroundColor($r('app.color.embellishment_color'))
          .fontColor($r('app.color.auxiliary_color'))
          .onClick(() => {
            this.loginTipCtrl.close();
            router.pushUrl({
              params:{
                isAgreement: true,
                agreementContent: "",
                icon: "",
                type: ["HWID_VERIFY_CODE","PHONE"]
              },
              url: '@bundle:com.jianguo.ai/common/ets/LoginComponent/LoginPage',
            })
          })
      }
      .width(GlobalConstant.PAGE_FULL)
      .justifyContent(FlexAlign.Center)
    }
    .width(GlobalConstant.PAGE_96)
    .padding({ bottom: GlobalConstant.SIZE_20 })
    .borderRadius(GlobalConstant.SIZE_16)
    .backgroundColor(Color.White)
  }
}

四、實現蜜蜂AI助手頁面

我們這個應用主要的一個功能就是AI助手,所以這一塊我們分為三塊。

1、蜜蜂AI列表頁

關于列表頁,我們使用一個列表就可以。

/**
 * 首頁
 */
import { ConfigConstant } from '../common/constants/ConfigConstant'
import { GlobalConstant } from '../common/constants/GlobalConstant'
import { AiAppConfig } from '../common/dto/AiAppConfig';
import router from '@ohos.router'
import { getDBPre } from '../common/api/PreDbService';
@Component
export struct HomeView {

  @State aiAppList: Array<AiAppConfig> = ConfigConstant.DEFAULT_AI_APP_LIST;

  }

  build() {
    Column() {
      List() {
        ForEach(this.aiAppList, (item: AiAppConfig) => {
          ListItem() {
            Row({ space: GlobalConstant.SIZE_8 }) {
              Row() {
                Image(item.avatar)
                  .width(GlobalConstant.SIZE_64)
                  .height(GlobalConstant.SIZE_64)
                  .borderRadius(GlobalConstant.SIZE_32)
              }
              .height(GlobalConstant.PAGE_FULL)
              .layoutWeight(1)
              Column({ space: GlobalConstant.SIZE_16 }) {
                Text(item.name)
                  .fontSize($r('app.float.font_size_18'))
                Text(item.intro)
                  .fontSize($r('app.float.font_size_14'))
                  .fontColor($r('app.color.text_color_9'))
              }
              .height(GlobalConstant.PAGE_FULL)
              .layoutWeight(3)
              .justifyContent(FlexAlign.Center)
              .alignItems(HorizontalAlign.Start)
            }
            .width(GlobalConstant.PAGE_96)
            .height(GlobalConstant.SIZE_100)
            .paddingStyle()
            .borderRadius(GlobalConstant.SIZE_16)
            .shadow({
              radius: GlobalConstant.SIZE_16,
              color: $r('app.color.main_color')
            })
            .onClick(() => {
              router.pushUrl({
                url: "pages/detail/index",
                params: {
                  "AiAppConfig": item
                }
              })
            })
          }
          .width(GlobalConstant.PAGE_FULL)
          .paddingStyle()
          .borderRadius(GlobalConstant.SIZE_16)
        })
      }
      .listDirection(Axis.Vertical)
      
    }
    .width(GlobalConstant.PAGE_FULL)
    .height(GlobalConstant.PAGE_FULL)
    .padding(GlobalConstant.SIZE_8)
  }


}

效果圖

HarmonyOS開發(fā)實例—蜜蜂AI助手

2、對話頁

關鍵代碼

build() {
    Column({ space: GlobalConstant.SIZE_8 }) {
      Stack({ alignContent: Alignment.Bottom }) {
        Column() {
          Column({ space: GlobalConstant.SIZE_4 }) {
            Text("蜜蜂AI助手")
              .fontSize($r('app.float.font_size_16'))
              .fontColor(Color.Black)
              .fontWeight(FontWeight.Bolder)
            Text("介紹")
              .fontSize($r('app.float.font_size_12'))
              .fontColor($r('app.color.text_color_9'))
              .fontWeight(FontWeight.Lighter)
          }
          .width(GlobalConstant.PAGE_FULL)
          .justifyContent(FlexAlign.Center)
          .padding({
            top: GlobalConstant.SIZE_4,
            bottom: GlobalConstant.SIZE_8
          })

          Scroll() {
            Column({ space: GlobalConstant.SIZE_8 }) {
              ForEach(this.chatContentArr, (chat: ChatInfo) => {
                if (chat.role === "assistant") {
                  Row() {
                    Row({ space: GlobalConstant.SIZE_8 }) {
                      Image(chat.avatar)
                        .width(GlobalConstant.SIZE_24)
                        .height(GlobalConstant.SIZE_24)
                      Row() {
                        Text(chat.content)
                          .fontSize($r('app.float.font_size_14'))
                          .fontColor(Color.Black)
                      }
                      .width(chat.content.length > 15 ? GlobalConstant.PAGE_76 : 'auto')
                      .backgroundColor($r('app.color.embellishment_color'))
                      .padding({
                        left: GlobalConstant.SIZE_16,
                        right: GlobalConstant.SIZE_16,
                        top: GlobalConstant.SIZE_8,
                        bottom: GlobalConstant.SIZE_8
                      })
                      .borderRadius({
                        topRight: GlobalConstant.SIZE_4,
                        bottomLeft: GlobalConstant.SIZE_8,
                        bottomRight: GlobalConstant.SIZE_4
                      })
                    }
                    .justifyContent(FlexAlign.Start)
                    .alignItems(VerticalAlign.Top)
                  }
                  .width(GlobalConstant.PAGE_FULL)
                  .justifyContent(FlexAlign.Start)
                }
                if (chat.role === "user") {
                  Row() {
                    Row({ space: GlobalConstant.SIZE_8 }) {
                      Row() {
                        Text(chat.content)
                          .fontSize($r('app.float.font_size_14'))
                          .fontColor(Color.Black)
                      }
                      .width(chat.content.length > 15 ? GlobalConstant.PAGE_76 : 'auto')
                      .backgroundColor($r('app.color.tab_default_color'))
                      .padding({
                        left: GlobalConstant.SIZE_16,
                        right: GlobalConstant.SIZE_16,
                        top: GlobalConstant.SIZE_8,
                        bottom: GlobalConstant.SIZE_8
                      })
                      .borderRadius({
                        topLeft: GlobalConstant.SIZE_4,
                        bottomLeft: GlobalConstant.SIZE_4,
                        bottomRight: GlobalConstant.SIZE_8
                      })
                      Image(chat.avatar)
                        .width(GlobalConstant.SIZE_24)
                        .height(GlobalConstant.SIZE_24)
                    }
                    .justifyContent(FlexAlign.End)
                    .alignItems(VerticalAlign.Top)
                  }
                  .width(GlobalConstant.PAGE_FULL)
                  .justifyContent(FlexAlign.End)
                }
              })
            }.width(GlobalConstant.PAGE_FULL)
          }
          .width(GlobalConstant.PAGE_96)
          .scrollable(ScrollDirection.Vertical)
          .flexShrink(1)
        }
        .width(GlobalConstant.PAGE_FULL)
        .height(GlobalConstant.PAGE_FULL)
        .padding({ bottom: GlobalConstant.SIZE_50 })

        Row({ space: GlobalConstant.SIZE_8 }) {
          TextInput({ placeholder: "請輸入提示詞...", text: this.inputValue })
            .height(GlobalConstant.SIZE_48)
            .fontSize($r('app.float.font_size_16'))
            .placeholderFont({ size: $r('app.float.font_size_16') })
            .placeholderColor($r('app.color.text_color_9'))
            .borderRadius($r('app.float.size_8'))
            .backgroundColor($r('app.color.card_bg_color'))
            .flexShrink(1)
            .onChange((value: string) => {
              this.inputValue = value;
            })
          Image($r('app.media.ic_send'))
            .width(GlobalConstant.SIZE_32)
            .height(GlobalConstant.SIZE_32)
            .onClick(async () => {
              this.loadingCtrl.open();
              if (this.inputValue === "") {
                promptAction.showToast({
                  message: "發(fā)送內容不能為空!"
                })
                return;
              }
              await this.getAiResult();
            })
        }
        .width(GlobalConstant.PAGE_FULL)
        .padding({
          left: GlobalConstant.SIZE_8,
          right: GlobalConstant.SIZE_8
        })
        .backgroundColor($r('app.color.card_bg_color'))
      }
      .width(GlobalConstant.PAGE_FULL)
      .height(GlobalConstant.PAGE_FULL)
    }
    .width(GlobalConstant.PAGE_FULL)
    .height(GlobalConstant.PAGE_FULL)
  }

效果圖

加載中:

HarmonyOS開發(fā)實例—蜜蜂AI助手

問答后:

HarmonyOS開發(fā)實例—蜜蜂AI助手

五、服務卡片

1、服務卡片

服務卡片(以下簡稱“卡片”)是一種界面展示形式,可以將應用的重要信息或操作前置到卡片,以達到服務直達、減少體驗層級的目的??ㄆS糜谇度氲狡渌麘茫ó斍翱ㄆ褂梅街恢С窒到y(tǒng)應用,如桌面)中作為其界面顯示的一部分,并支持拉起頁面、發(fā)送消息等基礎的交互功能。

服務卡片架構

下圖為服務卡片架構。

HarmonyOS開發(fā)實例—蜜蜂AI助手

另外了解卡片概念有助于我們更好的使用服務卡片。

卡片的基本概念:

  • 卡片使用方:如上圖中的桌面,顯示卡片內容的宿主應用,控制卡片在宿主中展示的位置。
  • 應用圖標:應用入口圖標,點擊后可拉起應用進程,圖標內容不支持交互。
  • 卡片:具備不同規(guī)格大小的界面展示,卡片的內容可以進行交互,如實現按鈕進行界面的刷新、應用的跳轉等。
  • 卡片提供方:包含卡片的應用,提供卡片的顯示內容、控件布局以及控件點擊處理邏輯。
  • FormExtensionAbility:卡片業(yè)務邏輯模塊,提供卡片創(chuàng)建、銷毀、刷新等生命周期回調。
  • 卡片頁面:卡片UI模塊,包含頁面控件、布局、事件等顯示和交互信息。

動態(tài)卡片事件能力說明

針對動態(tài)卡片,ArkTS卡片中提供了postCardAction()接口用于卡片內部和提供方應用間的交互,當前支持router、message和call三種類型的事件,僅在卡片中可以調用。后面我們也會用到這一塊的內容。

HarmonyOS開發(fā)實例—蜜蜂AI助手

2、服務卡片創(chuàng)建方式

創(chuàng)建工程時,選擇Atomic Service,默認自帶卡片,也可以在創(chuàng)建工程后右鍵新建卡片。

另外就是我們可能不止一個卡片,所以,后續(xù)我們可以這樣創(chuàng)建服務卡片。

HarmonyOS開發(fā)實例—蜜蜂AI助手

卡片相關的配置文件主要包含FormExtensionAbility的配置和卡片的配置兩部分。

卡片需要在module.json5配置文件中的extensionAbilities標簽下,配置FormExtensionAbility相關信息。FormExtensionAbility需要填寫metadata元信息標簽,其中鍵名稱為固定字符串“ohos.extension.form”,資源為卡片的具體配置信息的索引。

{
  "module": {
    ...
    "extensionAbilities": [
      {
        "name": "EntryFormAbility",
        "srcEntry": "./ets/entryformability/EntryFormAbility.ets",
        "label": "$string:EntryFormAbility_label",
        "description": "$string:EntryFormAbility_desc",
        "type": "form",
        "metadata": [
          {
            "name": "ohos.extension.form",
            "resource": "$profile:form_config"
          }
        ]
      }
    ]
  }
}

卡片的具體配置信息。在上述FormExtensionAbility的元信息(“metadata”配置項)中,可以指定卡片具體配置信息的資源索引。例如當resource指定為$profile:form_config時,會使用開發(fā)視圖的resources/base/profile/目錄下的form_config.json作為卡片profile配置文件。內部字段結構說明如下表所示。

卡片form_config.json配置文件

屬性名稱

含義

數據類型

是否可缺省

name

表示卡片的名稱,字符串最大長度為127字節(jié)。

字符串


description

表示卡片的描述。取值可以是描述性內容,也可以是對描述性內容的資源索引,以支持多語言。字符串最大長度為255字節(jié)。

字符串

可缺省,缺省為空。

src

表示卡片對應的UI代碼的完整路徑。當為ArkTS卡片時,完整路徑需要包含卡片文件的后綴,如:“./ets/widget/pages/WidgetCard.ets”。當為JS卡片時,完整路徑無需包含卡片文件的后綴,如:“./js/widget/pages/WidgetCard”

字符串


uiSyntax

表示該卡片的類型,當前支持如下兩種類型:- arkts:當前卡片為ArkTS卡片。- hml:當前卡片為JS卡片。

字符串

可缺省,缺省值為hml

window

用于定義與顯示窗口相關的配置。

對象

可缺省,缺省值見表2。

isDefault

表示該卡片是否為默認卡片,每個UIAbility有且只有一個默認卡片。- true:默認卡片。- false:非默認卡片。

布爾值


colorMode

表示卡片的主題樣式,取值范圍如下:- auto:跟隨系統(tǒng)的顏色模式值選取主題。- dark:深色主題。- light:淺色主題。

字符串

可缺省,缺省值為“auto”。

supportDimensions

表示卡片支持的外觀規(guī)格,取值范圍:- 1 * 2:表示1行2列的二宮格。- 2 * 2:表示2行2列的四宮格。- 2 * 4:表示2行4列的八宮格。- 4 * 4:表示4行4列的十六宮格。

字符串數組


defaultDimension

表示卡片的默認外觀規(guī)格,取值必須在該卡片supportDimensions配置的列表中。

字符串


updateEnabled

表示卡片是否支持周期性刷新(包含定時刷新和定點刷新),取值范圍:- true:表示支持周期性刷新,可以在定時刷新(updateDuration)和定點刷新(scheduledUpdateTime)兩種方式任選其一,當兩者同時配置時,定時刷新優(yōu)先生效。- false:表示不支持周期性刷新。

布爾類型


scheduledUpdateTime

表示卡片的定點刷新的時刻,采用24小時制,精確到分鐘。>說明:> updateDuration參數優(yōu)先級高于scheduledUpdateTime,兩者同時配置時,以updateDuration配置的刷新時間為準。

字符串

可缺省,缺省時不進行定點刷新。

updateDuration

表示卡片定時刷新的更新周期,單位為30分鐘,取值為自然數。當取值為0時,表示該參數不生效。當取值為正整數N時,表示刷新周期為30*N分鐘。>說明:> updateDuration參數優(yōu)先級高于scheduledUpdateTime,兩者同時配置時,以updateDuration配置的刷新時間為準。

數值

可缺省,缺省值為“0”。

formConfigAbility

表示卡片的配置跳轉鏈接,采用URI格式。

字符串

可缺省,缺省值為空。

metadata

表示卡片的自定義信息,參考Metadata數組標簽。

對象

可缺省,缺省值為空。

dataProxyEnabled

表示卡片是否支持卡片代理刷新,取值范圍:- true:表示支持代理刷新。- false:表示不支持代理刷新。設置為true時,定時刷新和下次刷新不生效,但不影響定點刷新。

布爾類型

可缺省,缺省值為false。

isDynamic

表示此卡片是否為動態(tài)卡片(僅針對ArkTS卡片生效)。- true:為動態(tài)卡片 。- false:為靜態(tài)卡片。

布爾類型

可缺省,缺省值為true。

transparencyEnabled

表示是否支持卡片使用方設置此卡片的背景透明度(僅對系統(tǒng)應用的ArkTS卡片生效。)。- true:支持設置背景透明度 。- false:不支持設置背景透明度。

布爾類型

可缺省,缺省值為false。

{
  "forms": [
    {
      "uiSyntax": "arkts",
      "isDefault": true,
      "defaultDimension": "1*2",
      "scheduledUpdateTime": "00:00",
      "src": "./ets/jianguoaizhushoutuijian/jianguoaizhushoutuijian.ets",
      "name": "jianguoaizhushoutuijian",
      "description": "蜜蜂AI助手推薦",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "supportDimensions": [
        "1*2"
      ],
      "updateEnabled": true,
      "updateDuration": 0
    },
    {
      "uiSyntax": "arkts",
      "isDefault": false,
      "defaultDimension": "2*2",
      "src": "./ets/jianguoaizhushou/jianguoaizhushou.ets",
      "name": "jianguoaizhushou",
      "description": "蜜蜂AI助手,幫你所幫",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "supportDimensions": [
        "2*2"
      ],
      "updateEnabled": false,
      "updateDuration": 0
    },
    {
      "name": "poetry",
      "description": "蜂蜜AI助手助你學妙語.",
      "src": "./ets/poetry/pages/PoetryCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": false,
      "updateEnabled": false,
      "scheduledUpdateTime": "10:30",
      "updateDuration": 1,
      "defaultDimension": "2*4",
      "supportDimensions": [
        "2*4"
      ]
    },
    {
      "name": "history",
      "description": "蜂蜜AI助手歷史記錄",
      "src": "./ets/history/pages/HistoryCard.ets",
      "uiSyntax": "arkts",
      "window": {
        "designWidth": 720,
        "autoDesignWidth": true
      },
      "colorMode": "auto",
      "isDefault": false,
      "updateEnabled": false,
      "scheduledUpdateTime": "10:30",
      "updateDuration": 1,
      "defaultDimension": "4*4",
      "supportDimensions": [
        "4*4"
      ]
    }
  ]
}

3、實現2*2/2*4/4*4服務卡片

1-2卡片

首先我們來看1-2卡片的實現。

@Entry
@Component
struct Jianguoaizhushoutuijian {
  private readonly PAGE_FULL: string = "100%";
  private readonly SIZE_4: number = 4;
  build() {
    Row({ space: this.SIZE_4 }) {
      Image('/common/imgs/ic_user.svg')
        .width($r('app.float.size_32'))
        .height($r('app.float.size_32'))

      Column() {
        Text('蜜蜂AI助手')
          .fontSize($r('app.float.font_size_14'))
          .fontColor($r('app.color.main_color'))
          .fontWeight(FontWeight.Bolder)

        Text('知識百科/文本翻譯/...')
          .fontSize($r('app.float.font_size_12'))
          .fontColor($r('app.color.text_color_9'))
      }
      .height(this.PAGE_FULL)
      .justifyContent(FlexAlign.Center)
      .alignItems(HorizontalAlign.Start)
    }    
    .width(this.PAGE_FULL)
    .height(this.PAGE_FULL)
    .padding({
      left: $r('app.float.size_8'),
      right: $r('app.float.size_8')
    })
    .onClick(() => {
      postCardAction(this, {
        "action": "router",
        "abilityName": "EntryAbility",
        "params": {}
      });
    })
  }
}
效果

實現效果如圖所示:

HarmonyOS開發(fā)實例—蜜蜂AI助手

原理

我可以用router來進行跳轉,默認不傳遞任何參數,就會跳轉到首頁。

.onClick(() => {
      postCardAction(this, {
        "action": "router",
        "abilityName": "EntryAbility",
        "params": {}
      });
    })

HarmonyOS開發(fā)實例—蜜蜂AI助手

2-4的卡片

我們來看妙語集這一個2-4卡片的實現。

完整代碼
const storage = new LocalStorage();
@Entry(storage)
@Component
struct PoetryCard {
  readonly PAGE_FULL: string = "100%";
  readonly PRE_96: string = "96%";
  readonly SIZE_40: number = 40;
  readonly SIZE_30: number = 30;
  readonly SIZE_20: number = 20;
  readonly SIZE_16: number = 16;
  readonly SIZE_8: number = 8;
  readonly SIZE_4: number = 4;

  @LocalStorageProp("poetry") poetry: any = {
    content: "秀樾橫塘十里香,水花晚色靜年芳。",
    author: "蔡松年",
    origin: "鷓鴣天·賞荷",
    category: "古詩文-四季-夏天"
  };

  build() {
    Column() {
      Row({ space: this.SIZE_8 }) {
        Image("/common/imgs/ic_ai_home.svg")
          .width(this.SIZE_20)
          .height(this.SIZE_20)
          .fillColor($r('app.color.text_font_color'))
        Text('妙語集')
          .fontSize($r('app.float.font_size_14'))
          .fontColor($r('app.color.text_font_color'))
      }
      .width(this.PAGE_FULL)
      .height(this.SIZE_40)
      .linearGradient({
        angle: 45,
        colors: [[$r('app.color.main_color'), 0.1], [$r('app.color.auxiliary_color'), 1.0]]
      })
      .padding({
        left: this.SIZE_16,
        right: this.SIZE_16
      })

      Column() {
        Stack({ alignContent: Alignment.TopEnd }) {
          Column({ space: this.SIZE_8 }) {
            Text(this.poetry['origin'])
              .fontSize($r('app.float.font_size_18'))
              .fontWeight(FontWeight.Bolder)
              .fontColor($r('app.color.text_color_title'))
            Text(this.poetry['author'])
              .fontSize($r('app.float.font_size_14'))
              .fontWeight(FontWeight.Medium)
              .fontColor($r('app.color.text_color_9'))

            Text(this.poetry['content'])
              .fontSize($r('app.float.font_size_16'))
              .fontColor($r('app.color.text_color_title'))
          }
          .width(this.PRE_96)
          .height(this.PRE_96)
          .justifyContent(FlexAlign.Center)
          Button({ type: ButtonType.Capsule }) {
            Image($r('app.media.ic_refreshing'))
              .width(this.SIZE_20)
              .height(this.SIZE_20)
              .fillColor(Color.White)
          }
          .width(this.SIZE_30).height(this.SIZE_30)
          .backgroundColor($r('app.color.tip_color'))
          .onClick(() => {
            postCardAction(this, {
              'action': 'message',
              'params': {
                'function': 'refreshing'
              }
            })
          })
        }
      }
      .width(this.PAGE_FULL)
      .flexShrink(1)
      .padding({top: this.SIZE_4, bottom: this.SIZE_8})
    }
    .width(this.PAGE_FULL)
    .height(this.PAGE_FULL)
  }
}
效果

HarmonyOS開發(fā)實例—蜜蜂AI助手

原理

我們是如何實現數據刷新的呢?

我們首先判斷返回的functionName,如果是refreshing,那么我們就去請求網絡接口,并完成數據的顯示和刷新。具體的關鍵代碼如下所示。

if (functionName === "refreshing") {
      fetchGetPoetry().then((ret) => {
        let formData = {
          poetry: {}
        }
        LogUtil.info(`widget refreshing: ${ret}`);
        const result = JSON.parse(ret as string);
        if (result.code === 200) {
          const poetry: PoetryDto = result['data'];
          formData.poetry = poetry;
        }
        let formBD = formBindingData.createFormBindingData(formData);
        formProvider.updateForm(formId, formBD);
      })
    }

HarmonyOS開發(fā)實例—蜜蜂AI助手

4-4的卡片

完整代碼:

@Entry
@Component
struct HistoryCard {

  readonly PAGE_FULL: string = "100%";
  readonly PRE_96: string = "96%";
  readonly SIZE_81: number = 81;
  readonly SIZE_64: number = 64;
  readonly SIZE_48: number = 48;
  readonly SIZE_32: number = 32;
  readonly SIZE_24: number = 24;
  readonly SIZE_16: number = 16;
  readonly SIZE_8: number = 8;
  readonly SIZE_4: number = 4;
  readonly DEFAULT_AI_APP_LIST: Array<AiAppConfig> = [
    {
      appId: "6548c7fdeb28cf9c75531f66",
      chatId: "",
      name: "知識百科小助手",
      avatar: "/common/imgs/ic_wiki.svg",
      intro: "知識百科小助手。"
    },
    {
      appId: "65488134eb28cf9c75530e48",
      chatId: "",
      name: "節(jié)日小助手",
      avatar: "/common/imgs/ic_festival.svg",
      intro: "節(jié)日小助手。"
    },
    {
      appId: "65487d64eb28cf9c75530cd2",
      chatId: "",
      name: "文本翻譯助手",
      avatar: "/common/imgs/ic_document.svg",
      intro: "文本翻譯助手。"
    },
    {
      appId: "654ed429ab7249585cd2cab7",
      chatId: "",
      name: "產品名稱助手",
      avatar: "/common/imgs/ic_product.svg",
      intro: "產品名稱助手。"
    },
    {
      appId: "654ed4c3ab7249585cd2caf4",
      chatId: "",
      name: "道歉信助手",
      avatar: "/common/imgs/ic_sorry.svg",
      intro: "道歉信助手。"
    }
  ];

  build() {
    Column({ space: this.SIZE_8 }) {
      Row({ space: this.SIZE_4 }) {
        Image($r('app.media.ic_history'))
          .width(this.SIZE_24)
          .height(this.SIZE_24)
          .fillColor($r('app.color.main_color'))
        Text('查看歷史數據')
          .fontSize($r('app.float.font_size_16'))
          .fontColor($r('app.color.main_color'))
          .fontWeight(FontWeight.Bolder)
      }
      .width(this.PAGE_FULL)
      .height(this.SIZE_48)
      .padding({ left: this.SIZE_16 })

      Column() {
        GridRow({
          columns: 3,
          gutter: { x: this.SIZE_4, y: this.SIZE_4 }
        }) {
          ForEach(this.DEFAULT_AI_APP_LIST, (item: AiAppConfig) => {
            GridCol() {
              Column({ space: this.SIZE_8 }) {
                Image(item.avatar)
                  .width(this.SIZE_32)
                  .height(this.SIZE_32)
                  .fillColor($r('app.color.main_color'))
                Text(item.name)
                  .fontSize($r('app.float.font_size_12'))
                  .fontColor($r('app.color.auxiliary_color'))
                  .fontWeight(FontWeight.Bold)
              }
              .width(this.PAGE_FULL)
              .height(this.SIZE_81)
              .justifyContent(FlexAlign.Center)
              .onClick(() => {
                postCardAction(this, {
                  'action': 'router',
                  'abilityName': 'HistoryAbility',
                  'params': {
                    'targetPage': 'history',
                    'aiApp': item
                  }
                })
              })
            }
            .borderRadius(this.SIZE_8)
            .padding({
              left: this.SIZE_4,
              right: this.SIZE_4,
              top: this.SIZE_8,
              bottom: this.SIZE_4
            })
            .shadow({
              radius: this.SIZE_8,
              color: $r('app.color.tab_default_color')
            })
          })
        }
      }
      .width(this.PRE_96)
      .justifyContent(FlexAlign.Center)
      .alignItems(HorizontalAlign.Center)
      .flexShrink(1)
    }
    .width(this.PAGE_FULL)
    .height(this.PAGE_FULL)
  }
}

/**
 * AI應用配置
 */
interface AiAppConfig {
  appId: string;  // AI應用AppId
  chatId: string; // 會話窗口ID
  name: string; // AI應用名稱
  avatar: string; // AI應用LOGO
  intro?: string;  // AI應用介紹
}

interface ChatHistory {
  chat: AiAppConfig;
  total: number;
}
效果

HarmonyOS開發(fā)實例—蜜蜂AI助手

原理

在卡片中使用postCardAction接口的router能力,能夠快速拉起卡片提供方應用的指定UIAbility,因此UIAbility較多的應用往往會通過卡片提供不同的跳轉按鈕,實現一鍵直達的效果。

通常使用按鈕控件來實現頁面拉起。

@Entry
@Component
struct WidgetCard {
  build() {
    Column() {
      Button('跳轉')
        .onClick(() => {
          console.info('Jump to EntryAbility funA');
          postCardAction(this, {
            action: 'router',
            abilityName: 'EntryAbility', // 只能跳轉到當前應用下的UIAbility
            params: {
              targetPage: 'funA' // 在EntryAbility中處理這個信息
            }
          });
        })
    }
    .width('100%')
    .height('100%').justifyContent(FlexAlign.SpaceAround)
  }
}
  • 在UIAbility中接收router事件并獲取參數,根據傳遞的params不同,選擇拉起不同的頁面。
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import Want from '@ohos.app.ability.Want';
import Base from '@ohos.base';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';

let selectPage: string = "";
let currentWindowStage: window.WindowStage | null = null;

export default class EntryAbility extends UIAbility {
  // 如果UIAbility第一次啟動,在收到Router事件后會觸發(fā)onCreate生命周期回調
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    // 獲取router事件中傳遞的targetPage參數
    console.info("onCreate want:" + JSON.stringify(want));
    if (want.parameters?.params !== undefined) {
      let params: Record<string, string> = JSON.parse(want.parameters?.params.toString());
      console.info("onCreate router targetPage:" + params.targetPage);
      selectPage = params.targetPage;
    }
  }
  // 如果UIAbility已在后臺運行,在收到Router事件后會觸發(fā)onNewWant生命周期回調
  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
    console.info("onNewWant want:" + JSON.stringify(want));
    if (want.parameters?.params !== undefined) {
      let params: Record<string, string> = JSON.parse(want.parameters?.params.toString());
      console.info("onNewWant router targetPage:" + params.targetPage);
      selectPage = params.targetPage;
    }
    if (currentWindowStage != null) {
      this.onWindowStageCreate(currentWindowStage);
    }
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    let targetPage: string;
    // 根據傳遞的targetPage不同,選擇拉起不同的頁面
    switch (selectPage) {
      case 'funA':
        targetPage = 'pages/FunA';
        break;
      case 'funB':
        targetPage = 'pages/FunB';
        break;
      default:
        targetPage = 'pages/Index';
    }
    if (currentWindowStage === null) {
      currentWindowStage = windowStage;
    }
    windowStage.loadContent(targetPage, (err: Base.BusinessError) => {
      if (err && err.code) {
        console.info('Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
    });
  }
};

六、總結

通過蜜蜂AI助手元服務的開發(fā),我們體驗到了端云一體化帶來的便捷,尤其注冊登陸這一塊,有了云端的接入,我們可以很快的加入。另外在項目里我們還用到了低碼能力,不用一行代碼,就完成了手機號登陸的功能。

本次鴻蒙和AI的結合,給了我新的體驗。大家也可以自行嘗試下HarmonyOS的開發(fā),會給你帶來不一樣的體驗。

想了解更多關于開源的內容,請訪問:

本站 鴻蒙開發(fā)者社區(qū)

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 美女脱了内裤打开腿让你桶爽 | 国产一久久香蕉国产线看观看 | 亚洲精品中文字幕久久久久久 | 成人精品一区久久久久 | 息与子中文字幕完整在线 | 亚洲欧美一区二区三区不卡 | 成人网址大全 | 九九精品视频一区二区三区 | 海绵宝宝第二季全集免费观看 | 欧美日韩视频在线一区二区 | 911福利视频 | 隔壁老王国产在线精品 | 图片专区小说专区卡通动漫 | 美女一级ba大片免色 | 午夜久 | 亚洲夜色夜色综合网站 | 色噜噜亚洲男人的天堂www | 青青成人福利国产在线视频 | 日韩国产欧美成人一区二区影院 | 国产精品视频免费视频 | 成人午夜爽爽爽免费视频 | 免费在线观看成年人视频 | 国产亚洲精品视频中文字幕 | 国产婷婷成人久久av免费高清 | 邪恶肉肉全彩色无遮盖 | 百合女女师生play黄肉黄 | 成人在线视频国产 | 亚洲高清成人 | 明星ai人脸替换造梦在线播放 | 91天堂国产在线 在线播放 | 国产一区私人高清影院 | 猛h辣h高h文湿校园1v1 | 亚洲国产日韩欧美mv | 亚洲天堂免费观看 | 日本在线观看www | 免费超级乱淫播放手机版 | 奇米影视小说 | 成年男女免费视频网站 | 女上男下gifxxoo动态视频 | 强女明星系列小说 | 91制片厂 果冻传媒 天美传媒 |